Comment extraire une colonne d'un fichier csv

Si j'ai un fichier csv, existe-t-il un moyen rapide d'imprimer le contenu d'une seule colonne? Il est prudent de supposer que chaque ligne a le même nombre de colonnes, mais le contenu de chaque colonne aurait une longueur différente.

66
demandé sur jww 2013-10-26 06:32:40

12 réponses

Vous pouvez utiliser awk pour cela. Changez '$ 2 ' à la nième colonne que vous voulez.

awk -F "\"*,\"*" '{print $2}' textfile.csv
75
répondu synthesizerpatel 2013-10-26 02:34:38

Oui. {[0] } affichera la 3ème colonne.

64
répondu madrag 2013-10-26 02:37:17

La façon la plus simple d'y parvenir était d'utiliser simplement csvtool. J'ai également eu d'autres cas d'utilisation pour utiliser csvtool et il peut gérer les guillemets ou les délimiteurs de manière appropriée s'ils apparaissent dans les données de la colonne elle-même.

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

Remplacer 2 par le numéro de colonne permet d'extraire efficacement les données de colonne que vous recherchez.

17
répondu Samar 2016-10-25 18:36:58

Atterri ici à la recherche d'extraire d'un fichier séparé par un onglet. Pensé que je pourrais ajouter.

cat textfile.tsv | cut -f2 -s

-f2 extrait la colonne indexée 2, non nulle, ou la deuxième colonne.

10
répondu cevaris 2014-04-18 20:28:33

Les autres réponses fonctionnent bien, mais puisque vous avez demandé une solution en utilisant uniquement le shell bash, vous pouvez le faire:

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

Et puis vous pouvez extraire des colonnes (les premières dans cet exemple) comme ceci:

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

Donc il y a quelques choses qui se passent ici:

  • while IFS=, - Cela dit d'utiliser une virgule comme IFS (séparateur de champ interne), ce que le shell utilise pour savoir ce qui sépare les champs (blocs de texte). Donc dire IFS=, c'est comme dire "a, b" est le même que "A b" serait si IFS= " "(ce qui est ce qu'il est par défaut.)

  • read -a csv_line; - c'est dire lire chaque ligne, un à la fois et de créer un tableau où chaque élément est appelé "csv_line" et l'envoyer à la "section" de notre boucle while

  • do echo "${csv_line[0]}";done < file - Maintenant, nous sommes dans la phase" do", et nous disons echo le 0ème élément du tableau "csv_line". Cette action est répétée sur chaque ligne du fichier. La partie < file indique simplement à la boucle while où Lire. NOTE: rappelez-vous, dans bash, les tableaux sont indexés à 0, donc la première colonne est le 0ème élément.

Donc là vous l'avez, en tirant une colonne d'un CSV dans le shell. Les autres solutions sont probablement plus pratiques, mais celle-ci est pure bash.

5
répondu drldcsta 2013-10-26 05:29:27

Beaucoup de réponses à ces questions sont grandes et certains ont même regardé dans les cas de coin. Je voudrais ajouter une réponse simple qui peut être d'usage quotidien... où vous entrez principalement dans ces cas de coin (comme avoir échappé des virgules ou des virgules entre guillemets, etc.,).

FS (séparateur de champs) est la variable dont la valeur est espace. Donc, awk par défaut se divise à l'espace pour n'importe quelle ligne.

Donc, en utilisant BEGIN (Execute avant de prendre input), nous pouvons définir ce champ sur tout ce que nous voulons...

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

Le code ci-dessus imprimera la 3ème colonne dans un fichier csv.

5
répondu router 2015-12-16 02:59:53

[dumb@one pts] $ cat > file #Nous allons d'abord créer un fichier CSV de base
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

[muet@one pts]$ awk -F '{print $1}' fichier
un
1
un
1

4
répondu Raj Velayudhan 2016-03-14 21:53:43

Vous pouvez utiliser GNU Awk, voir cet article du guide de l'utilisateur. Comme une amélioration de la solution présentée dans l'article (en juin 2015), la commande gawk suivante permet des guillemets doubles à l'intérieur des champs guillemets doubles; un guillemet double est marqué par deux guillemets doubles consécutifs ("") là. En outre, cela permet des champs vides, mais même cela ne peut pas gérer les champs multilignes . L'exemple suivant imprime la 3ème colonne (via c=3) de fichier texte.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)

Notez le utilisation de dos2unix pour convertir les sauts de ligne de style DOS possibles (CRLF, c'est-à-dire "\r\n") et l'encodage UTF-16 (avec marque d'ordre d'octet) en "\n" et UTF-8 (Sans marque d'ordre d'octet), respectivement. Les fichiers CSV Standard utilisent CRLF comme saut de ligne, Voir Wikipedia .

Si l'entrée peut contenir des champs multilignes, vous pouvez utiliser le script suivant. notez l'utilisation d'une chaîne spéciale pour séparer les enregistrements en sortie (puisque le retour à la ligne du séparateur par défaut peut se produire dans un enregistrement). Encore une fois, les éléments suivants exemple imprime la 3ème colonne (via c=3) de fichier texte.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)

Il y a une autre approche du problème. csvquote {[9] } peut afficher le contenu D'un fichier CSV modifié afin que les caractères spéciaux dans le champ soient transformés afin que les outils de traitement de texte Unix habituels puissent être utilisés pour sélectionner certaines colonnes. Par exemple, le code suivant génère la troisième colonne:

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

csvquote peut être utilisé pour traiter des fichiers volumineux arbitraires.

4
répondu jarno 2017-11-19 20:51:16

J'avais besoin D'une analyse CSV correcte, pas cut / awk et la prière. J'essaie cela sur un mac sans csvtool, mais les Mac viennent avec ruby, donc vous pouvez faire:

echo "require 'csv'; CSV.read('new.csv').each {|data| puts data[34]}" | ruby
2
répondu Darth Egregious 2018-02-23 15:07:01

Vous ne pouvez pas le faire sans un analyseur CSV complet.

1
répondu Peter Krumins 2016-12-26 01:22:23

Utilise ce code depuis un moment, il n'est pas "rapide" sauf si vous comptez "couper et coller de stackoverflow".

Il utilise les opérateurs $ { # # } et $ { % % } dans une boucle au lieu de IFS. Il appelle ' err ' et 'die', et ne supporte que la virgule, le tiret et le tuyau en tant que caractères SEP (c'est tout ce dont j'avais besoin).

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*}
}

Exemple:

$ 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
répondu qneill 2015-12-08 15:27:56
csvtool col 2 file.csv 

Où 2 est la colonne qui vous intéresse

Vous pouvez également faire

csvtool col 1,2 file.csv 

Pour faire plusieurs colonnes

0
répondu exussum 2018-09-04 09:08:46