So extrahieren Sie eine Spalte einer CSV-Datei


111

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:


135

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

13
echo '1,"2,3,4,5",6' | awk -F "\"*,\"*" '{print $2}'druckt 2statt 2,3,4,5.
Igor Mikushkin

Wenn Sie ein Glückspilz sind, der GNU Tools unter Windows verwendet, können Sie denselben Befehl wie @IgorMikushkin wie folgt ausführen:gawk -F"|" "{print $13}" files*.csv
Elidio Marquina

10
Ich denke, dies schlägt fehl, wenn es Zeichenfolgen gibt, die ein Komma enthalten, dh...,"string,string",...
Natriumnitrat

Ich denke, für die erste und letzte Spalte wird dies einen Fehler haben. Die erste Spalte beginnt mit "und die letzte endet mit"
BigTailWolf

Einige Programme geben CSV-Dateien mit unterschiedlichen Trennzeichen zurück. Daher muss der reguläre Ausdruck möglicherweise entsprechend geändert werden. Beispiel für ein Semikolon-Trennzeichen: awk -F "\"*;\"*" '{print $2}' textfile.csv
gekkedev

88

Ja. cat mycsv.csv | cut -d ',' -f3druckt die 3. Spalte.


8
Es sei denn, Spalte zwei enthält ein Komma. In diesem Fall erhalten Sie die zweite Hälfte von Spalte zwei. Fall in Punkt <col1>, "3.000", <col2>. Meine Antwort ist in Bezug auf dieses Problem jedoch nicht viel besser. Also nicht rausgeschmissen werden.
Synthesizerpatel

@synthesizerpatel Ich bin damit einverstanden, besser zu verwendenawk
MattSizzle

1
Wir sind nicht sicher, ob seine CSV-Datei doppelte Anführungszeichen enthält, um die unterschiedlichen Werte zu unterscheiden. Es wäre besser, wenn er eine Eingabedatei bereitstellt, damit wir die am besten geeignete Lösung bewerten können.
Idriss Neumann

50

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.


14
Dies sollte die akzeptierte Antwort sein. Dieses Tool kann mit CSV-Dateien umgehen, weit über die Behandlung eines Kommas als Feldtrennzeichen hinaus. Um die 2. Spalte zu extrahieren, "csvtool col 2 input.csv"
Vladislavs Dovgalecs

3
Nur ein Köpfchen entfernt ... Wenn Sie csvtool mit Standardeingabe verwenden möchten (Beispiel csv stammt von einem anderen Befehl), ist dies ungefähr so. 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.
General Redneck

Wenn es mehrzeilige Felder gibt, konnte der format '%(2)\n'Befehl nicht erkennen, wo ein Feld endet. (csvtool 1.4.2)
jarno

1
Neuere Versionen von csvtoolscheinen die Verwendung -als Eingabedateiname zum Lesen von stdin zu erfordern .
Connor Clark

@ GeneralRedneck warum Katze verwenden? und es ist Format nicht formathcsvtool format '%(1),%(10)\n' - < in.csv > out.csv
sijanec

14

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 -f2extrahiert die 2, nicht Null indizierte Spalte oder die zweite Spalte.


Einfach, auch der Punkt, und leichter anpassbar als die anderen Beispiele. Vielen Dank!
Nick Jennings

6
Nitpicking, ist aber catunnötig:< textfile.tsv cut -f2 -s
Anne van Rossum

8

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.


1
Ich habe es versucht und es werden immer noch Kommas in Anführungszeichen berücksichtigt.
Daniel C. Sobral

5

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 < fileTeil 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.


5

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.


5

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 ...]

4

Ich brauchte eine angemessene CSV-Analyse, nicht cut/ awkund 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

4

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

3
csvtool col 2 file.csv 

Dabei ist 2 die Spalte, an der Sie interessiert sind

Sie können auch tun

csvtool col 1,2 file.csv 

mehrere Spalten zu tun


3

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'


2

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

csvkit Dokumentation

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 csvcutDienstprogramm 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 

csvcut Referenzseite

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 csvkitoder sudo apt install csvkit.



0

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

0

Sie können auch die while-Schleife verwenden

IFS=,
while read name val; do
        echo "............................"

        echo Name: "$name"
done<itemlst.csv

Dieser Code erzeugt eine Shellcheck-Warnung: SC2034 . Die Suche gibt diese Frage als erstes Ergebnis zurück, wenn nach Möglichkeiten gesucht wird, die Warnung zu umgehen.
JWW
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.