Con GNU awk
:
watch -x gawk '
FNR == 17 {nextfile}
ENDFILE {if (FNR) printf "%15s[%02d] %s\n", FILENAME, FNR, $0}' ./*
Che dà un output come:
./file1[17] line17
./short-file2[05] line 5 is the last
Si noti che il ./*
glob viene espanso solo una volta al momento watch
viene richiamato.
La tua watch head -n 17 *
era una vulnerabilità di iniezione di comando arbitraria in quanto l'espansione di quella *
era in realtà interpretata come codice shell dalla shell che watch
invoca per interpretare la concatenazione dei suoi argomenti con spazi.
Se fosse presente un file chiamato $(reboot)
nella directory corrente, verrà riavviato.
Con -x
, stiamo dicendo watch
di saltare la shell ed eseguire direttamente il comando. In alternativa, potresti fare:
watch 'exec gawk '\''
FNR == 17 {nextfile}
ENDFILE {if (FNR) printf "%15s[%02d] %s\n", FILENAME, FNR, $0}'\'' ./*'
Per watch
eseguire una shell che espanderebbe quel ./*
glob ad ogni iterazione. watch foo bar
è in effetti lo stesso di watch -x sh -c 'foo bar'
. Quando si utilizza watch -x
, è possibile specificare quale shell si desidera e, ad esempio, sceglierne una più potente come zsh
quella può fare globbing ricorsivo e limitarsi ai file regolari:
watch -x zsh -c 'awk '\''...'\'' ./**/*(.)'
Senza gawk
, potresti ancora fare qualcosa del tipo:
watch '
for file in ./*; do
[ -s "$file" ] || continue
printf "%s: " "$file"
head -n 17 < "$file" | tail -n 1
done'
Dare un'uscita come:
./file1: line17
./short-file2: line 5 is the last
Ma sarebbe molto meno efficiente in quanto implica l'esecuzione di più comandi per file.
find . -exec
o sth in questo modo: D