Com o GNU awk
:
watch -x gawk '
FNR == 17 {nextfile}
ENDFILE {if (FNR) printf "%15s[%02d] %s\n", FILENAME, FNR, $0}' ./*
O que fornece uma saída como:
./file1[17] line17
./short-file2[05] line 5 is the last
Observe que a ./*
glob é expandida apenas uma vez no momento em que watch
é invocada.
Sua watch head -n 17 *
era uma vulnerabilidade de injeção de comando arbitrária, pois a expansão *
foi realmente interpretada como código do shell pelo shell que watch
invoca para interpretar a concatenação de seus argumentos com espaços.
Se houvesse um arquivo chamado $(reboot)
no diretório atual, ele seria reiniciado.
Com -x
, estamos dizendo watch
para pular o shell e executar o comando diretamente. Como alternativa, você pode fazer:
watch 'exec gawk '\''
FNR == 17 {nextfile}
ENDFILE {if (FNR) printf "%15s[%02d] %s\n", FILENAME, FNR, $0}'\'' ./*'
Para watch
executar um shell que expandiria esse ./*
globo a cada iteração. watch foo bar
é efetivamente o mesmo que watch -x sh -c 'foo bar'
. Ao usar watch -x
, você pode especificar qual shell você deseja e, por exemplo, escolher um shell mais poderoso como zsh
esse que pode fazer globbing recursivo e restringir a arquivos regulares:
watch -x zsh -c 'awk '\''...'\'' ./**/*(.)'
Sem gawk
, você ainda pode fazer algo como:
watch '
for file in ./*; do
[ -s "$file" ] || continue
printf "%s: " "$file"
head -n 17 < "$file" | tail -n 1
done'
Dando uma saída como:
./file1: line17
./short-file2: line 5 is the last
Mas isso seria muito menos eficiente, pois implica na execução de vários comandos por arquivo.
find . -exec
ou sth como este: DCombine
head
etail
como nestes dois exemplos:Portanto, para resolver seu problema real, o comando é:
Observe a
2>/dev/null
peça, é necessária porque * corresponderá aos diretórios e aos arquivos que você talvez não tenha permissão para ler, o que produzirá uma mensagem de erro que provavelmente você deseja ocultar.fonte
outra abordagem com find, exec e sed
fonte