it-swarm.com.de

So extrahieren Sie eine Spalte einer CSV-Datei

Wenn ich eine CSV-Datei habe, gibt es eine schnelle Bash-Methode, um den Inhalt nur einer einzelnen Spalte auszudrucken? Es kann davon ausgegangen werden, dass jede Zeile die gleiche Anzahl von Spalten hat, aber der Inhalt jeder Spalte hätte eine andere Länge.

77
user788171

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
89

ja. cat mycsv.csv | cut -d ',' -f3 druckt die 3. Spalte.

66
madrag

Die einfachste Möglichkeit, 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 entsprechend behandeln, wenn sie in den Spaltendaten selbst erscheinen.

csvtool format '%(2)\n' input.csv

Durch Ersetzen von 2 durch die Spaltennummer werden die gewünschten Spaltendaten effektiv extrahiert.

22
Samar

Ist hier gelandet und sucht aus einer tabulatorgetrennten Datei Dachte ich würde hinzufügen. 

cat textfile.tsv | cut -f2 -s

Dabei -f2 extrahiert die 2, nicht null indizierte Spalte oder die zweite Spalte. 

12
cevaris

Viele Antworten auf diese Fragen sind großartig und einige haben sich sogar mit den Eckfällen befasst. Ich möchte eine einfache Antwort hinzufügen, die für den täglichen Gebrauch geeignet sein kann ... wo Sie meistens in solche Eckfälle geraten (z. B. durch Kommas oder Kommas in Anführungszeichen entkommen usw.).

FS (Field Separator) ist die Variable, deren Wert auf .__ festgelegt ist. Platz. Daher teilt sich awk standardmäßig in den Abstand für eine beliebige Zeile.

Wenn Sie BEGIN (Ausführen vor der Eingabe) verwenden, können Sie dieses Feld beliebig festlegen.

awk 'BEGIN {FS = ","}; {print $3}'

Der obige Code druckt die 3. Spalte in einer CSV-Datei.

5
router

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

Es gibt also ein paar Dinge hier: 

  • while IFS=, - Dies bedeutet, dass als IFS (Internal Field Separator) ein Komma verwendet wird. Dies ist, was die Shell verwendet, um zu wissen, was Felder (Textblöcke) voneinander trennen. Wenn also IFS =, ist das Gleiche wie "a, b", dann ist "a b" dasselbe, wenn IFS = "" (was standardmäßig ist.) 

  • read -a csv_line; - Dies bedeutet, dass in jeder Zeile nacheinander gelesen und ein Array erstellt wird, in dem jedes Element "csv_line" genannt wird, und es an den Abschnitt "do" unserer while-Schleife sendet

  • do echo "${csv_line[0]}";done < file - jetzt sind wir in der "do" -Phase, und wir sagen, dass das 0-te Element des Arrays "csv_line" wiederholt wird. Diese Aktion wird in jeder Zeile der Datei wiederholt. Der < file-Teil sagt nur der while-Schleife, wo gelesen werden soll. ANMERKUNG: Denken Sie daran, dass in Bash-Arrays 0 indiziert sind, sodass die erste Spalte das 0-te Element ist. 

Also haben Sie es, eine Spalte aus einer CSV in der Shell herauszuziehen. Die anderen Lösungen sind wahrscheinlich praktischer, aber diese ist reine Bash. 

5
drldcsta

Sie könnten GNU Awk, siehe diesen Artikel des Benutzerhandbuchs ..__ verwenden. Als Verbesserung der im Artikel (im Juni 2015) vorgestellten Lösung ermöglicht der folgende Befehl gawk doppelte Anführungszeichen innerhalb von double zitierte Felder; Ein Anführungszeichen wird dort durch zwei aufeinanderfolgende Anführungszeichen ("") markiert. Außerdem erlaubt dies leere Felder, , aber selbst das kann keine mehrzeiligen Felder verarbeiten. Im folgenden Beispiel wird die 3. Spalte (über c=3) von textfile.csv gedruckt:

#!/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 DOS-Zeilenumbrüche (CRLF, dh "\ r\n") und UTF-16-Codierung (mit Byte-Reihenfolge) in "\ n" bzw. UTF-8 (ohne Byte-Reihenfolge) 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 der standardmäßige Trennstrich für Zeilenumbrüche innerhalb eines Datensatzes auftreten kann). Im folgenden Beispiel wird die dritte Spalte (über c=3) von textfile.csv erneut gedruckt:

#!/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 so ausgeben, dass die Sonderzeichen innerhalb des Felds so umgewandelt werden, dass die üblichen Unix-Textverarbeitungstools zur Auswahl bestimmter Spalten verwendet werden können. Beispielsweise gibt der folgende Code die dritte Spalte aus:

csvquote textfile.csv | cut -d ',' -f 3 | csvquote -u

csvquote kann verwendet werden, um beliebige große Dateien zu verarbeiten.

5
jarno

[dumm @ one pts] $ cat> Datei #First erstellen wir eine Basis-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

[dumm @ one pts] $ awk -F, '{print $ 1}' Datei
ein
1
ein
1

4
Raj Velayudhan

Ich brauchte die richtige CSV-Analyse, nicht cut/awk und Gebet. Ich versuche dies auf einem Mac ohne csvtool, aber Macs kommen mit Ruby, also können Sie:

echo "require 'csv'; CSV.read('new.csv').each {|data| puts data[34]}" | Ruby
2
Darth Egregious

Ohne einen vollständigen CSV-Parser ist dies nicht möglich.

1
Peter Krumins
csvtool col 2 file.csv 

dabei ist 2 die Kolumne, an der Sie interessiert sind

du kannst es auch tun 

csvtool col 1,2 file.csv 

mehrere Spalten machen 

1
exussum

Ich denke, die einfachste 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'

0
wordsforthewise

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

Um die erste Spalte zu erhalten, verwenden Sie:

cut -d, -f1 myTooth.csv

f steht für Field und d steht für Trennzeichen

Durch Ausführen des obigen Befehls wird die folgende Ausgabe erzeugt.

Ausgabe

Date
2017-01-25
2017-02-19
2017-02-24
2017-02-28

Um nur die 2. Spalte zu erhalten:

cut -d, -f2 myTooth.csv

Und hier ist die Ausgabe Ausgabe

Tooth
wisdom
canine
canine
wisdom
incisor

Ein anderer Anwendungsfall:

Ihre CSV-Eingabedatei enthält 10 Spalten. Sie möchten die Spalten 2 bis 5 und 8, wobei Komma als Trennzeichen verwendet wird.

cut verwendet -f (Bedeutung "Felder") zur Angabe von Spalten und -d (Bedeutung "Trennzeichen") zur Angabe des Trennzeichens. Letzteres muss angegeben werden, da einige Dateien Leerzeichen, Tabulatoren oder Doppelpunkte verwenden, um die Spalten voneinander zu trennen.

cut -f 2-5,8 -d , myvalues.csv

cut ist ein Befehlsprogramm und hier einige weitere Beispiele:

SYNOPSIS
     cut -b list [-n] [file ...]
     cut -c list [file ...]
     cut -f list [-d delim] [-s] [file ...]
0
Stryker

Wenn Sie diesen Code für eine Weile verwenden, ist er nicht "schnell", es sei denn, Sie zählen "Ausschneiden und Einfügen aus Stackoverflow".

Es verwendet die Operatoren $ {##} und $ {%%} in einer Schleife anstelle von IFS. Er ruft 'err' und 'die' auf und unterstützt als SEP - Zeichen nur Komma, Bindestrich und Pipe (das ist alles was ich brauche).

err()  { echo "${0##*/}: Error:" "[email protected]" >&2; }
die()  { err "[email protected]"; 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
qneill

Ich frage mich, warum in keiner der Antworten bisher csvkit erwähnt wurde. 

csvkit ist eine Suite von Befehlszeilentools zum Konvertieren in und zum Arbeiten mit mit CSV

csvkit Dokumentation

Ich verwende es ausschließlich für die Verwaltung von csv-Daten und bisher habe ich 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 cvscut-Dienstprogramm verwenden, das Teil der Toolbox ist. Um die zweite Spalte zu extrahieren, verwenden Sie diesen Befehl:

cvscut -c 2 filename_in.csv > filename_out.csv 

csvcut-Referenzseite

0

Sie können auch while-Schleife verwenden

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

        echo Name: "$name"
done<itemlst.csv
0
K. Sopheak