web-dev-qa-db-fra.com

Comment extraire une colonne d'un fichier csv

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

77
user788171

Vous pouvez utiliser awk pour cela. Remplacez '$ 2' par la nième colonne souhaitée.

awk -F "\"*,\"*" '{print $2}' textfile.csv
89
synthesizerpatel

oui. cat mycsv.csv | cut -d ',' -f3 imprimera la 3ème colonne.

66
madrag

La façon la plus simple de réaliser cela était d’utiliser simplement csvtool . J'avais également d'autres cas d'utilisation pour utiliser csvtool et celui-ci peut gérer les guillemets ou les délimiteurs de manière appropriée s'ils apparaissent dans les données de colonne elles-mêmes.

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

Si vous remplacez 2 par le numéro de colonne, les données de colonne recherchées seront extraites.

22
Samar

A atterri ici cherchant à extraire d'un fichier séparé par des tabulations. Je pensais ajouter. 

cat textfile.tsv | cut -f2 -s

-f2 extrait les 2 ou la deuxième colonne indexée, différente de zéro. 

12
cevaris

Beaucoup de réponses à ces questions sont excellentes et certaines ont même jeté un œil dans les cas les plus critiques. Je voudrais ajouter une réponse simple qui peut être d'usage quotidien ... où vous tombez principalement dans ces virages (comme avoir échappé des virgules ou des virgules, etc.).

FS (Field Separator) est la variable dont la valeur est définie sur espace. Donc, awk par défaut se divise en espace pour n'importe quelle ligne.

Donc, en utilisant BEGIN (Exécuter avant de prendre une entrée), nous pouvons définir ce champ à tout ce que nous voulons ...

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

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

5
router

Les autres réponses fonctionnent bien, mais puisque vous avez demandé une solution en utilisant uniquement le bash Shell, 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 (la première 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

Il y a donc deux choses qui se passent ici: 

  • while IFS=, - Cela veut dire utiliser une virgule comme IFS (séparateur de champs internes), 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 identique à "a b" serait si IFS = "" (ce qui est ce qu'il est par défaut). 

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

  • do echo "${csv_line[0]}";done < file - nous sommes maintenant dans la phase "do" et nous disons que echo est 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 que dans bash, les tableaux ont la valeur 0 indexé, la première colonne est donc le 0e élément. 

Vous avez donc maintenant extrait une colonne d'un fichier CSV dans le shell. Les autres solutions sont probablement plus pratiques, mais celle-ci est pure bash. 

5
drldcsta

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

Notez l'utilisation de dos2unix pour convertir les sauts de ligne de style DOS possibles (CRLF c'est-à-dire "\ r\n") et le codage UTF-16 (avec marque d'ordre des octets) en "\ n" et UTF-8 (sans marque d'ordre des octets), 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 dans la sortie (car le retour à la ligne par défaut du séparateur pourrait se produire dans un enregistrement). De nouveau, l'exemple suivant imprime la 3ème colonne (via c=3) de 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)

Il existe une autre approche du problème. csvquote peut afficher le contenu d'un fichier CSV modifié de manière à transformer les caractères spéciaux du champ 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.

5
jarno

[dumb @ one pts] $ cat> fichier # Tout d'abord, nous allons 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

[dumb @ one pts] $ awk -F, fichier '{print $ 1}'
une
1
une
1

4
Raj Velayudhan

J'avais besoin d'une analyse CSV appropriée, pas de cut/awk et de la prière. J'essaye ceci sur un mac sans csvtool, mais les macs viennent avec Ruby, donc vous pouvez faire:

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

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

1
Peter Krumins
csvtool col 2 file.csv 

où 2 est la colonne qui vous intéresse

tu peux aussi faire 

csvtool col 1,2 file.csv 

faire plusieurs colonnes 

1
exussum

Je pense que le plus simple est d'utiliser csvkit :

Obtient la 2ème colonne: csvcut -c 2 file.csv

Cependant, il y a aussi csvtool , et probablement un certain nombre d'autres outils de csv bash:

Sudo apt-get install csvtool (pour les systèmes basés sur Debian)

Cela renverrait une colonne avec la première ligne ayant un "ID". csvtool namedcol ID csv_file.csv

Cela renverrait la quatrième ligne: csvtool col 4 csv_file.csv

Si vous souhaitez supprimer la ligne d'en-tête:

csvtool col 4 csv_file.csv | sed '1d'

0
wordsforthewise

Voici un exemple de fichier csv à 2 colonnes

myTooth.csv

Date,Tooth
2017-01-25,wisdom
2017-02-19,canine
2017-02-24,canine
2017-02-28,wisdom

Pour obtenir la première colonne, utilisez:

cut -d, -f1 myTooth.csv

f représente le champ et d le délimiteur

L'exécution de la commande ci-dessus produira la sortie suivante.

Sortie

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

Pour obtenir la 2ème colonne uniquement:

cut -d, -f2 myTooth.csv

Et voici la sortie Sortie

Tooth
wisdom
canine
canine
wisdom
incisor

Un autre cas d'utilisation:

Votre fichier d’entrée csv contient 10 colonnes et vous voulez les colonnes 2 à 5 et 8, en utilisant une virgule comme séparateur ".

cut utilise -f (signification "champs") pour spécifier les colonnes et -d (signification "délimiteur") pour spécifier le séparateur. Vous devez spécifier ce dernier point car certains fichiers peuvent utiliser des espaces, des tabulations ou des deux-points pour séparer les colonnes.

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

cut est un utilitaire de commande et voici quelques exemples supplémentaires:

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

En utilisant ce code depuis un certain temps, il n’est "rapide" que si vous comptez "couper et coller à partir de stackoverflow".

Il utilise les opérateurs $ {##} et $ {%%} dans une boucle au lieu de IFS. Il appelle 'err' et 'die', et ne prend en charge que les caractères virgule, tiret et pipe sous la forme 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
qneill

Je me demande pourquoi aucune des réponses à ce jour n’a mentionné csvkit. 

csvkit est une suite d’outils de ligne de commande permettant de convertir et de travailler avec CSV

documentation csvkit

Je l'utilise exclusivement pour la gestion de données csv et, jusqu'à présent, je n'ai pas trouvé de problème que je n'ai pas pu résoudre avec cvskit.

Pour extraire une ou plusieurs colonnes d'un fichier cvs, vous pouvez utiliser l'utilitaire cvscut qui fait partie de la boîte à outils. Pour extraire la deuxième colonne, utilisez cette commande:

cvscut -c 2 filename_in.csv > filename_out.csv 

Page de référence csvcut

0
Andreas Sumerauer

Vous pouvez également utiliser la boucle while

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

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