С GNU awk
:
watch -x gawk '
FNR == 17 {nextfile}
ENDFILE {if (FNR) printf "%15s[%02d] %s\n", FILENAME, FNR, $0}' ./*
Который дает вывод как:
./file1[17] line17
./short-file2[05] line 5 is the last
Обратите внимание, что ./*
глобус расширяется только один раз в тот момент, когда watch
вызывается.
Ваша watch head -n 17 *
уязвимость была связана с произвольным введением команд, поскольку расширение, которое *
фактически интерпретировалось оболочкой как код оболочки, watch
вызывает интерпретацию объединения аргументов с пробелами.
Если $(reboot)
в текущем каталоге был вызван файл , он перезагрузился бы.
С помощью -x
мы говорим watch
пропустить оболочку и выполнить команду напрямую. В качестве альтернативы вы можете сделать:
watch 'exec gawk '\''
FNR == 17 {nextfile}
ENDFILE {if (FNR) printf "%15s[%02d] %s\n", FILENAME, FNR, $0}'\'' ./*'
Для watch
запуска оболочки, которая будет расширять этот ./*
шар на каждой итерации. watch foo bar
в действительности так же, как watch -x sh -c 'foo bar'
. При использовании watch -x
вы можете указать, какая оболочка вам нужна, и, например, выбрать более мощную, например zsh
, такую, которая может выполнять рекурсивное сглаживание и ограничиваться обычными файлами:
watch -x zsh -c 'awk '\''...'\'' ./**/*(.)'
Без gawk
, вы все еще можете сделать что-то вроде:
watch '
for file in ./*; do
[ -s "$file" ] || continue
printf "%s: " "$file"
head -n 17 < "$file" | tail -n 1
done'
Давать выходной как:
./file1: line17
./short-file2: line 5 is the last
Но это было бы намного менее эффективно, так как подразумевает выполнение нескольких команд на файл.
find . -exec
например, так: D