Con GNU awk
:
watch -x gawk '
FNR == 17 {nextfile}
ENDFILE {if (FNR) printf "%15s[%02d] %s\n", FILENAME, FNR, $0}' ./*
Lo que da una salida como:
./file1[17] line17
./short-file2[05] line 5 is the last
Tenga en cuenta que el ./*
globo se expande solo una vez cuando watch
se invoca.
Tuviste watch head -n 17 *
una vulnerabilidad de inyección de comando arbitraria, ya que la expansión de eso en *
realidad fue interpretada como código de shell por el shell que watch
invoca para interpretar la concatenación de sus argumentos con espacios.
Si hubiera un archivo llamado $(reboot)
en el directorio actual, se reiniciaría.
Con -x
, le estamos diciendo watch
que omita el shell y ejecute el comando directamente. Alternativamente, puedes hacer:
watch 'exec gawk '\''
FNR == 17 {nextfile}
ENDFILE {if (FNR) printf "%15s[%02d] %s\n", FILENAME, FNR, $0}'\'' ./*'
Para watch
ejecutar un shell que expandiría ese ./*
globo en cada iteración. watch foo bar
en efecto es lo mismo que watch -x sh -c 'foo bar'
. Al usarlo watch -x
, puede especificar qué shell desea y, por ejemplo, elegir uno más potente como zsh
ese puede hacer globbing recursivo y restringirlo a archivos normales:
watch -x zsh -c 'awk '\''...'\'' ./**/*(.)'
Sin gawk
, aún podrías hacer algo como:
watch '
for file in ./*; do
[ -s "$file" ] || continue
printf "%s: " "$file"
head -n 17 < "$file" | tail -n 1
done'
Dando una salida como:
./file1: line17
./short-file2: line 5 is the last
Pero eso sería mucho menos eficiente, ya que implica ejecutar varios comandos por archivo.
find . -exec
algo como esto: DCombina
head
y datail
like en estos dos ejemplos:Entonces, para resolver su problema real, el comando es:
Tenga en cuenta la
2>/dev/null
parte, es necesario porque * coincidirá con los directorios y cualquier archivo que no tenga permiso para leer, lo que producirá un mensaje de error, que probablemente quiera ocultar.fuente
otro enfoque con find, exec y sed
fuente