Wenn ich eine CSV-Datei habe, gibt es eine schnelle Möglichkeit, den Inhalt nur einer einzelnen Spalte auszudrucken? Es ist davon auszugehen, dass jede Zeile die gleiche Anzahl von Spalten hat, der Inhalt jeder Spalte jedoch eine andere Länge hat.
Wenn ich eine CSV-Datei habe, gibt es eine schnelle Möglichkeit, den Inhalt nur einer einzelnen Spalte auszudrucken? Es ist davon auszugehen, dass jede Zeile die gleiche Anzahl von Spalten hat, der Inhalt jeder Spalte jedoch eine andere Länge hat.
Antworten:
Sie könnten awk dafür verwenden. Ändern Sie '$ 2' in die n-te Spalte, die Sie möchten.
awk -F "\"*,\"*" '{print $2}' textfile.csv
gawk -F"|" "{print $13}" files*.csv
...,"string,string",...
"
und die letzte endet mit"
awk -F "\"*;\"*" '{print $2}' textfile.csv
Ja. cat mycsv.csv | cut -d ',' -f3
druckt die 3. Spalte.
awk
Der einfachste Weg, dies zu erreichen, war die Verwendung von csvtool . Ich hatte auch andere Anwendungsfälle, um csvtool zu verwenden, und es kann die Anführungszeichen oder Trennzeichen angemessen behandeln, wenn sie in den Spaltendaten selbst erscheinen.
csvtool format '%(2)\n' input.csv
Durch Ersetzen von 2 durch die Spaltennummer werden die gesuchten Spaltendaten effektiv extrahiert.
cat input.csv | csvtool formath '%(2)\n' -
Hinweis Ich weiß, dass cat hier nutzlos ist, aber für jeden Befehl, der normalerweise eine csv exportieren würde.
format '%(2)\n'
Befehl nicht erkennen, wo ein Feld endet. (csvtool 1.4.2)
csvtool
scheinen die Verwendung -
als Eingabedateiname zum Lesen von stdin zu erfordern .
csvtool format '%(1),%(10)\n' - < in.csv > out.csv
Hier gelandet, um aus einer durch Tabulatoren getrennten Datei zu extrahieren. Ich dachte, ich würde hinzufügen.
cat textfile.tsv | cut -f2 -s
Wobei -f2
extrahiert die 2, nicht Null indizierte Spalte oder die zweite Spalte.
cat
unnötig:< textfile.tsv cut -f2 -s
Viele Antworten auf diese Fragen sind großartig und einige haben sogar die Eckfälle untersucht. Ich möchte eine einfache Antwort hinzufügen, die von täglichem Nutzen sein kann ... wo Sie meistens in diese Eckfälle geraten (wie Kommas oder Kommas in Anführungszeichen usw.).
FS (Field Separator) ist die Variable, deren Wert standardmäßig auf Leerzeichen gesetzt ist. Also teilt awk standardmäßig das Leerzeichen für jede Zeile auf.
Mit BEGIN (Ausführen vor Eingabe) können wir dieses Feld auf alles setzen, was wir wollen ...
awk 'BEGIN {FS = ","}; {print $3}'
Der obige Code druckt die 3. Spalte in einer CSV-Datei.
Die anderen Antworten funktionieren gut, aber da Sie nur mit der Bash-Shell nach einer Lösung gefragt haben, können Sie Folgendes tun:
AirBoxOmega:~ d$ cat > file #First we'll create a basic CSV
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
Und dann können Sie Spalten (die erste in diesem Beispiel) wie folgt herausziehen:
AirBoxOmega:~ d$ while IFS=, read -a csv_line;do echo "${csv_line[0]}";done < file
a
1
a
1
a
1
a
1
a
1
a
1
Hier sind also ein paar Dinge los:
while IFS=,
- Dies bedeutet, dass ein Komma als IFS (Internal Field Separator) verwendet wird. Dies ist das, was die Shell verwendet, um zu wissen, was Felder (Textblöcke) trennt. Wenn Sie also IFS = sagen, ist das wie "a, b" dasselbe wie "a b", wenn IFS = "" (was standardmäßig der Fall ist).
read -a csv_line;
- Dies bedeutet, dass Sie jede Zeile einzeln einlesen und ein Array erstellen, in dem jedes Element "csv_line" heißt, und das an den Abschnitt "do" unserer while-Schleife senden
do echo "${csv_line[0]}";done < file
- Jetzt befinden wir uns in der "do" -Phase und sagen, dass das 0. Element des Arrays "csv_line" wiedergegeben wird. Diese Aktion wird in jeder Zeile der Datei wiederholt. Der < file
Teil sagt nur der while-Schleife, woher sie lesen soll. HINWEIS: Denken Sie daran, dass in Bash Arrays mit 0 indiziert sind, sodass die erste Spalte das 0. Element ist.
Da haben Sie es also, indem Sie eine Spalte aus einer CSV in der Shell herausziehen. Die anderen Lösungen sind wahrscheinlich praktischer, aber diese ist reine Bash.
Sie können GNU Awk verwenden, siehe diesen Artikel im Benutzerhandbuch . Als Verbesserung der im Artikel (im Juni 2015) vorgestellten Lösung ermöglicht der folgende Befehl gawk doppelte Anführungszeichen in Feldern mit doppelten Anführungszeichen. Ein doppeltes Anführungszeichen wird dort durch zwei aufeinanderfolgende doppelte Anführungszeichen ("") gekennzeichnet. Darüber hinaus erlaubt dies leere Felder, aber auch dies kann keine mehrzeiligen Felder verarbeiten . Das folgende Beispiel druckt die 3. Spalte (via c=3
) von textfile.csv:
#!/bin/bash
gawk -- '
BEGIN{
FPAT="([^,\"]*)|(\"((\"\")*[^\"]*)*\")"
}
{
if (substr($c, 1, 1) == "\"") {
$c = substr($c, 2, length($c) - 2) # Get the text within the two quotes
gsub("\"\"", "\"", $c) # Normalize double quotes
}
print $c
}
' c=3 < <(dos2unix <textfile.csv)
Beachten Sie die Verwendung von dos2unix
, um mögliche Zeilenumbrüche im DOS-Stil (CRLF, dh "\ r \ n") und UTF-16-Codierung (mit Byte-Ordnungsmarke) in "\ n" bzw. UTF-8 (ohne Byte-Ordnungsmarke) zu konvertieren. Standard-CSV-Dateien verwenden CRLF als Zeilenumbruch, siehe Wikipedia .
Wenn die Eingabe mehrzeilige Felder enthalten kann, können Sie das folgende Skript verwenden. Beachten Sie die Verwendung einer speziellen Zeichenfolge zum Trennen von Datensätzen in der Ausgabe (da die Standard-Trennzeichen-Zeilenumbruch innerhalb eines Datensatzes auftreten kann). Das folgende Beispiel druckt erneut die 3. Spalte (via c=3
) von textfile.csv:
#!/bin/bash
gawk -- '
BEGIN{
RS="\0" # Read the whole input file as one record;
# assume there is no null character in input.
FS="" # Suppose this setting eases internal splitting work.
ORS="\n####\n" # Use a special output separator to show borders of a record.
}
{
nof=patsplit($0, a, /([^,"\n]*)|("(("")*[^"]*)*")/, seps)
field=0;
for (i=1; i<=nof; i++){
field++
if (field==c) {
if (substr(a[i], 1, 1) == "\"") {
a[i] = substr(a[i], 2, length(a[i]) - 2) # Get the text within
# the two quotes.
gsub(/""/, "\"", a[i]) # Normalize double quotes.
}
print a[i]
}
if (seps[i]!=",") field=0
}
}
' c=3 < <(dos2unix <textfile.csv)
Es gibt einen anderen Ansatz für das Problem. csvquote kann den Inhalt einer CSV-Datei ausgeben, die so geändert wurde, dass Sonderzeichen im Feld so transformiert werden, dass mit den üblichen Unix-Textverarbeitungswerkzeugen bestimmte Spalten ausgewählt werden können. Der folgende Code gibt beispielsweise die dritte Spalte aus:
csvquote textfile.csv | cut -d ',' -f 3 | csvquote -u
csvquote
kann verwendet werden, um beliebig große Dateien zu verarbeiten.
Hier ist ein Beispiel für eine CSV-Datei mit 2 Spalten
myTooth.csv
Date,Tooth
2017-01-25,wisdom
2017-02-19,canine
2017-02-24,canine
2017-02-28,wisdom
Verwenden Sie zum Abrufen der ersten Spalte:
cut -d, -f1 myTooth.csv
f steht für Field und d steht für Trennzeichen
Wenn Sie den obigen Befehl ausführen, wird die folgende Ausgabe erzeugt.
Ausgabe
Date
2017-01-25
2017-02-19
2017-02-24
2017-02-28
So erhalten Sie nur die 2. Spalte:
cut -d, -f2 myTooth.csv
Und hier ist die Ausgabe Ausgabe
Tooth
wisdom
canine
canine
wisdom
incisor
Ein weiterer Anwendungsfall:
Ihre CSV-Eingabedatei enthält 10 Spalten und Sie möchten die Spalten 2 bis 5 und die Spalten 8, wobei Komma als Trennzeichen verwendet wird. "
cut verwendet -f (bedeutet "Felder"), um Spalten anzugeben, und -d (bedeutet "Trennzeichen"), um das Trennzeichen anzugeben. Sie müssen Letzteres angeben, da einige Dateien möglicherweise Leerzeichen, Tabulatoren oder Doppelpunkte verwenden, um Spalten zu trennen.
cut -f 2-5,8 -d , myvalues.csv
cut ist ein Befehlsdienstprogramm und hier einige weitere Beispiele:
SYNOPSIS
cut -b list [-n] [file ...]
cut -c list [file ...]
cut -f list [-d delim] [-s] [file ...]
Ich brauchte eine angemessene CSV-Analyse, nicht cut
/ awk
und Gebet. Ich versuche dies auf einem Mac ohne csvtool
, aber Macs werden mit Ruby geliefert, sodass Sie Folgendes tun können:
echo "require 'csv'; CSV.read('new.csv').each {|data| puts data[34]}" | ruby
Zuerst erstellen wir eine grundlegende CSV
[dumb@one pts]$ cat > file
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
Dann bekommen wir die 1. Spalte
[dumb@one pts]$ awk -F , '{print $1}' file
a
1
a
1
Ich denke, am einfachsten ist die Verwendung von csvkit :
Ruft die 2. Spalte ab:
csvcut -c 2 file.csv
Es gibt jedoch auch csvtool und wahrscheinlich eine Reihe anderer csv-Bash-Tools:
sudo apt-get install csvtool
(für Debian-basierte Systeme)
Dies würde eine Spalte mit der ersten Zeile mit 'ID' zurückgeben.
csvtool namedcol ID csv_file.csv
Dies würde die vierte Zeile zurückgeben:
csvtool col 4 csv_file.csv
Wenn Sie die Kopfzeile löschen möchten:
csvtool col 4 csv_file.csv | sed '1d'
Ich frage mich, warum in keiner der Antworten bisher csvkit erwähnt wurde.
csvkit ist eine Suite von Befehlszeilentools zum Konvertieren in und Arbeiten mit CSV
Ich benutze es ausschließlich für die Verwaltung von CSV-Daten und habe bisher kein Problem gefunden, das ich mit cvskit nicht lösen konnte.
Um eine oder mehrere Spalten aus einer CVS-Datei zu extrahieren, können Sie das csvcut
Dienstprogramm verwenden, das Teil der Toolbox ist. Verwenden Sie diesen Befehl, um die zweite Spalte zu extrahieren:
csvcut -c 2 filename_in.csv > filename_out.csv
Wenn die Zeichenfolgen in der CSV in Anführungszeichen stehen, fügen Sie das Anführungszeichen mit dem hinzu q
Option hinzu:
csvcut -q '"' -c 2 filename_in.csv > filename_out.csv
Installieren mit pip install csvkit
oder sudo apt install csvkit
.
Ohne einen vollständigen CSV-Parser ist dies nicht möglich.
cut
?
Wenn Sie diesen Code schon eine Weile verwenden, ist er nicht "schnell", es sei denn, Sie zählen "Ausschneiden und Einfügen aus dem Stapelüberlauf".
Es werden die Operatoren $ {##} und $ {%%} in einer Schleife anstelle von IFS verwendet. Es ruft 'err' und 'die' auf und unterstützt nur Komma, Bindestrich und Pipe als SEP-Zeichen (das ist alles, was ich brauche).
err() { echo "${0##*/}: Error:" "$@" >&2; }
die() { err "$@"; exit 1; }
# Return Nth field in a csv string, fields numbered starting with 1
csv_fldN() { fldN , "$1" "$2"; }
# Return Nth field in string of fields separated
# by SEP, fields numbered starting with 1
fldN() {
local me="fldN: "
local sep="$1"
local fldnum="$2"
local vals="$3"
case "$sep" in
-|,|\|) ;;
*) die "$me: arg1 sep: unsupported separator '$sep'" ;;
esac
case "$fldnum" in
[0-9]*) [ "$fldnum" -gt 0 ] || { err "$me: arg2 fldnum=$fldnum must be number greater or equal to 0."; return 1; } ;;
*) { err "$me: arg2 fldnum=$fldnum must be number"; return 1;} ;;
esac
[ -z "$vals" ] && err "$me: missing arg2 vals: list of '$sep' separated values" && return 1
fldnum=$(($fldnum - 1))
while [ $fldnum -gt 0 ] ; do
vals="${vals#*$sep}"
fldnum=$(($fldnum - 1))
done
echo ${vals%%$sep*}
}
Beispiel:
$ CSVLINE="example,fields with whitespace,field3"
$ $ for fno in $(seq 3); do echo field$fno: $(csv_fldN $fno "$CSVLINE"); done
field1: example
field2: fields with whitespace
field3: field3
Sie können auch die while-Schleife verwenden
IFS=,
while read name val; do
echo "............................"
echo Name: "$name"
done<itemlst.csv
echo '1,"2,3,4,5",6' | awk -F "\"*,\"*" '{print $2}'
druckt2
statt2,3,4,5
.