Primero, un descargo de responsabilidad: no analice la salida de find
. El siguiente código es solo ilustrativo, de cómo incorporar la sustitución de comandos en un script Awk de tal manera que los comandos puedan actuar sobre partes de la entrada de Awk.
Para realmente hacer un recuento de la línea ( wc -l
) en cada archivo encontrado con find
(que es el caso del ejemplo del uso), sólo tiene que utilizar:
find . -type f -name '*txt' -exec wc -l {} +
Sin embargo, para responder sus preguntas como se le preguntó:
Q1
Para responder a su Q1:
P1: ¿hay alguna manera de realizar la sustitución de comandos dentro de awk?
Por supuesto que hay una manera, desde man awk
:
comando | getline [var] Ejecutar comando canalizando la salida en $ 0 o var, como se indica arriba, y RT.
Entonces (¡Mira la cita!):
find . | awk '/txt$/{"wc -l <\"" $NF "\"|cut -f1" | getline(nl); print(nl)}'
Tenga en cuenta que la cadena creada y, por lo tanto, el comando ejecutado es
wc -l <file
Para evitar la impresión de nombre de archivo de wc
.
Bueno, evité un archivo "cerrar" necesario para ese comando (seguro para un par de archivos, pero técnicamente incorrecto). Realmente necesitas hacer:
find . | awk '/txt$/{
comm="wc -l <\"" $NF "\" | cut -f1"
comm | getline nl;
close (comm);
print nl
}'
Eso también funciona para versiones anteriores de awk.
Recuerde evitar la impresión de un punto .
con find .
, eso hace que el código falle ya que un punto es un directorio y wc no puede usar eso.
O bien, evite el uso de valores de puntos:
find . | awk '/txt$/ && $NF!="." { comm="wc -l <\"" $NF "\" | cut -f1"
comm | getline nl;
close (comm);
print nl
}'
Puedes convertir eso en una línea, pero se verá bastante feo, piensa Me.
Q2
En cuanto a tu segunda pregunta:
P2: ¿por qué el primer encantamiento anterior falla silenciosamente y simplemente imprime los nombres de archivo?
Porque awk no analiza correctamente los comandos de shell. Entiende el comando como:
nl = $(wc -l $NF)
nl --> variable
$ --> pointer to a field
wc --> variable (that has zero value here)
- --> minus sign
l --> variable (that has a null string)
$ --> Pointer to a field
NF --> Last field
Luego, se l $NF
convierte en la concatenación de nulo y el texto dentro del campo las (un nombre de un archivo). La expansión de dicho texto como variable numérica es el valor numérico 0
Para awk, se convierte en:
nl = $( wc -l $NF)
nl = $ ( 0 - 0 )
Que se convierte en justo $0
, la entrada de línea completa, que es (por el simple hallazgo de arriba) solo el nombre del archivo.
Entonces, todo lo anterior solo imprimirá el nombre del archivo (bueno, técnicamente, toda la línea).
for
ejemplo de bucle: ¿Por qué es un bucle sobre la salida de find una mala práctica?