Imprimir colunas no awk pelo nome do cabeçalho

11

Eu tenho um arquivo de texto assim

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

Posso usar o awk para imprimir determinadas colunas, como 1 e 3, com {print $1, $3}, mas quero especificar as colunas a serem impressas especificando o cabeçalho da coluna, algo como {print $foo, $baz}. Isso é útil, portanto, não preciso abrir o arquivo e contar as colunas manualmente para ver qual coluna é qual e não preciso atualizar o script se o número ou a ordem da coluna mudar. Posso fazer isso com o awk (ou outra ferramenta shell)?

user1350864
fonte

Respostas:

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

Esse é um idioma imensamente útil. Eu tenho muitos dados em planilhas e diferentes planilhas podem ter um subconjunto comum de colunas nas quais estou interessado, mas não necessariamente na mesma ordem em todas as planilhas ou com o mesmo número de outras colunas antes / entre elas para poder exportar eles como CSV ou similar e simplesmente executar um script awk usando os nomes das colunas em vez dos números das colunas é absolutamente inestimável.

Ed Morton
fonte
Isso é muito obrigado e funciona para meus propósitos. Você é capaz de esclarecer como isso funciona para um iniciante desajeitado? O que a sintaxe f [$ i] está fazendo nisso e como o awk calcula quais colunas correspondem às strings?
AlexLipp
Seja bem-vindo. Essa é a sintaxe absolutamente básica do awk, basta procurar campos e matrizes na página de manual do awk (ou no google). Adicionar print ie print $ie print f [$ i] `instruções no loop, etc. para rastrear o que está acontecendo se isso ajuda.
Ed Morton
0

Você pede awk, mas você também pode usar uma ferramenta mais especializada para isso: csvtool.

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

ou

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

Supondo que o arquivo seja um arquivo TSV ("valores separados por tabulação"), usando csvkit:

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

A saída será CSV formatada corretamente, mas poderá ser facilmente alterada novamente para TSV:

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

A -copção csvcuttambém pode receber números e intervalos e também pode ser usada para reorganizar as colunas dos dados de entrada (um recurso que muitas vezes sinto falta no cututilitário padrão ).

Kusalananda
fonte