Primeiro, um aviso de isenção: Por favor, não analise a saída de find
. O código abaixo é apenas para ilustração, de como incorporar a substituição de comandos em um script Awk de tal maneira que os comandos possam atuar sobre partes da entrada do Awk.
Para realmente fazer uma contagem de linha ( wc -l
) em cada arquivo encontrado com find
(que é o caso de uso de exemplo), use:
find . -type f -name '*txt' -exec wc -l {} +
No entanto, para responder às suas perguntas conforme solicitado:
Q1
Para responder ao seu primeiro trimestre:
Q1: is there a way to perform command substitution inside awk?
Claro que existe uma maneira, de man awk
:
command | getline [var] Run command piping the output either into $0 or var, as above, and RT.
Então (veja a citação !!):
find . | awk '/txt$/{"wc -l <\"" $NF "\"|cut -f1" | getline(nl); print(nl)}'
Por favor, note que a string construída e, portanto, o comando executado é
wc -l <file
Para evitar a impressão do nome do arquivo de wc
.
Bem, evitei um arquivo "fechado" necessário para esse comando (seguro para alguns arquivos, mas tecnicamente incorreto). Você realmente precisa fazer:
find . | awk '/txt$/{
comm="wc -l <\"" $NF "\" | cut -f1"
comm | getline nl;
close (comm);
print nl
}'
Isso também funciona para versões antigas do awk.
Lembre-se de evitar a impressão de um ponto .
com find .
, que faz o código falhar como um ponto é um diretório e wc não pode usar isso.
Ou, evite o uso de valores de ponto:
find . | awk '/txt$/ && $NF!="." { comm="wc -l <\"" $NF "\" | cut -f1"
comm | getline nl;
close (comm);
print nl
}'
Você pode converter isso para um de uma linha, mas vai parecer bem feio, pensa Me.
Q2
Quanto à sua segunda pergunta:
Q2: why is the first incantation above silently failing and is simply printing the filenames instead?
Porque o awk não analisa corretamente os comandos do shell. Entenda o comando como:
nl = $(wc -l $NF)
nl --> variable
$ --> pointer to a field
wc --> variable (that has zero value here)
- --> minus sign
l --> variable (that has a null string)
$ --> Pointer to a field
NF --> Last field
Em seguida, l $NF
se torna a concatenação de null e o text dentro do campo las (um nome de um arquivo). A expansão desse texto como uma variável numérica é o valor numérico 0
Para awk, torna-se:
nl = $( wc -l $NF)
nl = $ ( 0 - 0 )
O que se torna apenas $0
, toda a entrada de linha, que é (para a simples descoberta acima) apenas o nome do arquivo.
Assim, todos os itens acima só imprimirão o nome do arquivo (bem, tecnicamente, toda a linha).