web-dev-qa-db-fra.com

Extraire des colonnes spécifiques d'un fichier délimité en utilisant Awk

Désolé si c'est trop basique. J'ai un fichier CSV où les colonnes ont une ligne d'en-tête (v1, v2, etc.). Je comprends que pour extraire les colonnes 1 et 2, je dois faire: awk -F "," '{print $1 "," $2}' infile.csv > outfile.csv. Mais que se passe-t-il si je dois extraire, par exemple, les colonnes 1 à 10, 20 à 25 et 30, 33? En tant qu'additif, existe-t-il un moyen d'extraire directement avec les noms d'en-tête plutôt qu'avec les numéros de colonne?

32
user702432

Je ne sais pas s'il est possible de faire des gammes dans awk. Vous pouvez faire une boucle for, mais vous devez ajouter un traitement pour filtrer les colonnes que vous ne voulez pas. C'est probablement plus facile à faire:

awk -F, '{OFS=",";print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$20,$21,$22,$23,$24,$25,$30,$33}' infile.csv > outfile.csv

autre chose à considérer - et ceci plus rapide et plus concis:

cut -d "," -f1-10,20-25,30-33 infile.csv > outfile.csv

En ce qui concerne la deuxième partie de votre question, j'écrirais probablement un script en Perl qui sait comment gérer les lignes d'en-tête, en analysant les noms de colonnes de stdin ou d'un fichier, puis en effectuant le filtrage. C'est probablement un outil que je voudrais avoir pour d'autres choses. Je ne suis pas sûr de pouvoir faire un aller simple, même si je suis sûr que cela peut être fait.

51
Cliff

Comme mentionné par @Tom, les approches cut et awk ne fonctionnent pas pour les CSV contenant des chaînes entre guillemets. Une alternative est un module pour python qui fournit l'outil de ligne de commande csvfilter. Cela fonctionne comme couper, mais gère correctement les colonnes CSV citant:

csvfilter -f 1,3,5 in.csv > out.csv

Si vous avez Python (et vous devriez le faire), vous pouvez l'installer simplement comme ceci:

pip install csvfilter

Veuillez noter que l'indexation des colonnes dans csvfilter commence par 0 (contrairement à awk, qui commence par $ 1). Plus d'infos sur https://github.com/codeinthehole/csvfilter/

11
studgeek

D'autres ont répondu à votre question précédente. Pour ça:

En tant qu'additif, existe-t-il un moyen d'extraire directement avec les noms d'en-tête plutôt qu'avec les numéros de colonne?

Je ne l'ai pas essayé, mais vous pouvez stocker l'index de chaque en-tête dans un hachage, puis utiliser ce hachage pour obtenir son index ultérieurement.

for(i=0;i<$NF;i++){
    hash[$i] = i;
}

Puis plus tard, utilisez-le:

j = hash["header1"];
print $j;
3
Ritesh

D'autres langues ont des raccourcis pour les plages de numéros de champs, mais pas awk, vous devrez écrire votre code comme peur

awk -F, 'BEGIN {OFS=","} { print $1, $2, $3, $4 ..... $30, $33}' infile.csv > outfile.csv

Awk n'a pas pour fonction directe d'utiliser les noms de champs comme spécificateurs de colonnes.

J'espère que ça aide.

3
shellter

Vous pouvez utiliser une boucle for pour adresser un champ avec $ i :

ls -l | awk '{for(i=3 ; i<8 ; i++) {printf("%s\t", $i)} print ""}'
2
Raymond Hettinger

Tabulator est un ensemble d’outils de ligne de commande unix permettant de travailler avec des fichiers CSV comportant des lignes d’en-tête. Voici un exemple pour extraire des colonnes par nom à partir d'un fichier test.csv:

name,sex,house_nr,height,shoe_size
arthur,m,42,181,11.5
berta,f,101,163,8.5
chris,m,1333,175,10
don,m,77,185,12.5
elisa,f,204,166,7

Alors tblmap -k name,height test.csv produit

name,height
arthur,181
berta,163
chris,175
don,185
elisa,166
1
stefan.schroedl

Ne pas utiliser awk mais le moyen le plus simple de le faire était d’utiliser simplement csvtool . J'avais également d'autres cas d'utilisation pour utiliser csvtool, qui 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
csvtool format '%(2),%(3),%(4)\n' input.csv

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

0
Samar