¿Hay alguna manera de realizar la sustitución de comandos dentro de AWK y poder hacer referencia a los campos dentro del comando sustituido utilizando la $n
notación de AWK?
P.ej
find | awk '/txt$/ {nl = $(wc -l $NF); print nl}'
Esperaba que lo anterior imprimiera el número de líneas en cada .txt
archivo. En cambio, devuelve efectivamente el mismo resultado que:
find | awk '/txt$/ {print}'
P1: ¿hay alguna manera de realizar la sustitución de comandos dentro de awk?
P2: ¿por qué el primer encantamiento anterior falla silenciosamente y simplemente imprime los nombres de archivo?
Tenga en cuenta que lo anterior se ofrece solo a modo de ejemplo. No estoy preguntando cómo imprimir el número de líneas de cada archivo por algún otro medio. Ej. Porfor f in $(find -iname \*.txt); do wc -l $f; done
La pregunta es específicamente sobre cómo aprovechar la sustitución de comandos en los programas AWK.
for
ejemplo de bucle: ¿Por qué es un bucle sobre la salida de find una mala práctica?wc -l $f
sin citar"$f"
.for
bucle de ejemplo se puede resolver con solofind . -type f -name '*txt' -exec wc -l {} +
wc -l **/*txt
con globstar activado en bash y construcciones similares en otros shells, si los nombres de archivo combinados no exceden ARG_MAX.Respuestas:
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 confind
(que es el caso del ejemplo del uso), sólo tiene que utilizar:Sin embargo, para responder sus preguntas como se le preguntó:
Q1
Para responder a su Q1:
Por supuesto que hay una manera, desde
man awk
:Entonces (¡Mira la cita!):
Tenga en cuenta que la cadena creada y, por lo tanto, el comando ejecutado es
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:
Eso también funciona para versiones anteriores de awk.
Recuerde evitar la impresión de un punto
.
confind .
, 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:
Puedes convertir eso en una línea, pero se verá bastante feo, piensa Me.
Q2
En cuanto a tu segunda pregunta:
Porque awk no analiza correctamente los comandos de shell. Entiende el comando como:
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 0Para awk, se convierte en:
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).
fuente
Use en
"weak quotes"
lugar de la'strong quotes'
expansión de subshell dentro de unawk
script, pero hacerlo en su ejemplo no sería una implementación particularmente valiosa. También se ve fantásticamente feo:fuente
$n
notación. Por ejemplo,ls | awk "{ print \"$(echo hello $NF)\"} "
no imprime el nombre de cada archivo después del "hola"$
modo quebash
no lo consuma antes deawk
poder verlo. E incluso entonces, la subshell no sabe que está dentroawk
, por lo que cualquierawk
análisis sería después de cualquier procesamiento de shell. Porprint \$$(echo 1)
lo tanto, debe reducirse aprint $1
.