Avec GNU awk
:
watch -x gawk '
FNR == 17 {nextfile}
ENDFILE {if (FNR) printf "%15s[%02d] %s\n", FILENAME, FNR, $0}' ./*
Ce qui donne une sortie comme:
./file1[17] line17
./short-file2[05] line 5 is the last
Notez que le ./*
glob n'est développé qu'une seule fois au moment de l' watch
appel.
Your watch head -n 17 *
était une vulnérabilité d'injection de commande arbitraire, car son expansion *
était en fait interprétée comme du code shell par le shell qui watch
invoque pour interpréter la concaténation de ses arguments avec des espaces.
S'il y avait un fichier appelé $(reboot)
dans le répertoire courant, il redémarrerait.
Avec -x
, nous disons watch
de sauter le shell et d'exécuter directement la commande. Alternativement, vous pouvez faire:
watch 'exec gawk '\''
FNR == 17 {nextfile}
ENDFILE {if (FNR) printf "%15s[%02d] %s\n", FILENAME, FNR, $0}'\'' ./*'
Pour watch
exécuter un shell qui développerait ce ./*
glob à chaque itération. watch foo bar
est en fait le même que watch -x sh -c 'foo bar'
. Lors de l'utilisation watch -x
, vous pouvez spécifier le shell que vous voulez et par exemple en choisir un plus puissant comme zsh
celui-ci peut faire un globbing récursif et restreindre aux fichiers réguliers:
watch -x zsh -c 'awk '\''...'\'' ./**/*(.)'
Sans gawk
, vous pourriez toujours faire quelque chose comme:
watch '
for file in ./*; do
[ -s "$file" ] || continue
printf "%s: " "$file"
head -n 17 < "$file" | tail -n 1
done'
Donner une sortie comme:
./file1: line17
./short-file2: line 5 is the last
Mais ce serait beaucoup moins efficace car cela implique d'exécuter plusieurs commandes par fichier.
find . -exec
ou quelque chose comme ça: D