Imprimer les colonnes dans awk par nom d'en-tête

11

J'ai un fichier texte comme ça

foo bar baz
1   a   alpha
2   b   beta
3   c   gamma

Je peux utiliser awk pour imprimer certaines colonnes, comme 1 et 3, avec {print $1, $3}, mais je veux spécifier les colonnes à imprimer en spécifiant à la place l'en-tête de la colonne, quelque chose comme {print $foo, $baz}. Ceci est utile, donc je n'ai pas à ouvrir le fichier et à compter les colonnes manuellement pour voir quelle colonne est laquelle, et je n'ai pas à mettre à jour le script si le numéro de colonne ou l'ordre change. Puis-je le faire avec awk (ou un autre outil shell)?

user1350864
la source

Réponses:

16
awk '
NR==1 {
    for (i=1; i<=NF; i++) {
        f[$i] = i
    }
}
{ print $(f["foo"]), $(f["baz"]) }
' file
foo baz
1 alpha
2 beta
3 gamma

C'est un idiome extrêmement utile. J'ai beaucoup de données dans des feuilles de calcul et différentes feuilles de calcul peuvent avoir un sous-ensemble commun de colonnes qui m'intéresse, mais pas nécessairement dans le même ordre sur toutes les feuilles de calcul ou avec le même nombre d'autres colonnes avant / entre elles afin de pouvoir exporter les CSV ou similaires, puis exécutez simplement un script awk en utilisant les noms de colonnes au lieu des numéros de colonnes est absolument inestimable.

Ed Morton
la source
C'est un grand merci et fonctionne pour mes besoins. Êtes-vous en mesure de clarifier comment cela fonctionne pour un débutant awk? Que fait la syntaxe f [$ i] à cet égard et comment awk détermine-t-il quelles colonnes correspondent aux chaînes?
AlexLipp
Vous êtes les bienvenus. C'est une syntaxe awk absolument basique, il suffit de rechercher les champs et les tableaux dans la page de manuel awk (ou sur google). Ajoutez des instructions print iet print $iet print f [$ i] `dans la boucle, etc. pour suivre ce qui se passe si cela vous aide.
Ed Morton
0

Vous demandez awk, mais vous pouvez également utiliser un outil plus spécialisé pour cela: csvtool.

csvtool -t ' ' -u ' ' namedcol foo,baz file

ou

csvtool -t ' ' -u ' ' col 1,3 file
pLumo
la source
0

En supposant que le fichier est un fichier TSV ("valeurs séparées par des tabulations"), en utilisant csvkit:

$ csvcut -t -c foo,baz file.tsv
foo,baz
1,alpha
2,beta
3,gamma

La sortie sera correctement formatée CSV, mais pourrait facilement être modifiée en TSV:

$ csvcut -t -c foo,baz file.tsv | csvformat -T
foo     baz
1       alpha
2       beta
3       gamma

L' -coption de csvcutpeut également prendre des nombres et des plages, et peut également être utilisée pour réorganiser les colonnes des données d'entrée (une fonctionnalité qui me manque souvent dans l' cututilitaire standard ).

Kusalananda
la source