Pase la variable de shell como a / patrón / a awk


59

Tener lo siguiente en una de mis funciones de shell:

function _process () {
  awk -v l="$line" '
  BEGIN {p=0}
  /'"$1"'/ {p=1}
  END{ if(p) print l >> "outfile.txt" }
  '
}

, así que cuando se llama como _process $arg, $argse pasa como $1y se usa como patrón de búsqueda. Funciona de esta manera, ¡porque la carcasa se expande $1en lugar del patrón awk! También lse puede usar dentro del programa awk, declarándose con -v l="$line". Todo muy bien.

¿Es posible de la misma manera dar un patrón para buscar como variable?

Seguir no funcionará,

awk -v l="$line" -v search="$pattern" '
  BEGIN {p=0}
  /search/ {p=1}
  END{ if(p) print l >> "outfile.txt" }
  '

, como awk no se interpretará /search/como una variable, sino literalmente.

Respuestas:


46

Utilice el ~operador de awk , y no necesita proporcionar una expresión regular literal en el lado derecho:

function _process () {
    awk -v l="$line" -v pattern="$1" '
        $0 ~ pattern {p=1} 
        END {if(p) print l >> "outfile.txt"}
    '  
}

Aunque esto sería más eficiente (no tiene que leer todo el archivo)

function _process () {
    grep -q "$1" && echo "$line"
}

Dependiendo del patrón, puede querer grep -Eq "$1"


Esto es exactamente lo que resuelve esto de la manera que quería (primer ejemplo), porque mantiene la semántica, que era mi objetivo. Gracias.
branquito

1
No noté la eliminación del bloque BEGIN: una variable no asignada se trata como 0 en un contexto numérico o la cadena vacía de lo contrario. Entonces, una variable no asignada será falsa enif (p) ...
glenn jackman

Sí, lo noté, debe establecerse en el bloque BEGIN a cero cada vez, ya que sirve como un interruptor. Pero, curiosamente, intenté usar script ahora $0 ~ pattern, y no funciona, ¡¿pero /'"$1"'/sí funciona ?! : O
branquito

tal vez tiene algo que ver con la forma en que $linese recupera, la búsqueda de patrones se realiza en la salida de whois $line, $lineproveniente del archivo en un bloque WHILE DO.
branquito

Muestre el contenido de $line: hágalo en su pregunta para obtener el formato adecuado.
Glenn Jackman

17
awk  -v pattern="$1" '$0 ~ pattern'

Tiene un problema que awkexpande las secuencias de escape ANSI C (como \npara nueva línea, \fpara alimentación de formulario, \\para barra diagonal inversa, etc.) en $1. Por lo tanto, se convierte en un problema si $1contiene caracteres de barra diagonal inversa que es común en las expresiones regulares (con GNU awk4.2 o superior, los valores que comienzan @/y terminan en /, también son un problema ). Otro enfoque que no sufre de ese problema es escribirlo:

PATTERN=$1 awk '$0 ~ ENVIRON["PATTERN"]'

Lo malo que será dependerá de la awkimplementación.

$ nawk -v 'a=\.' 'BEGIN {print a}'
.
$ mawk -v 'a=\.' 'BEGIN {print a}'
\.
$ gawk -v 'a=\.' 'BEGIN {print a}'
gawk: warning: escape sequence `\.' treated as plain `.'
.
$ gawk5.0.1 -v 'a=@/foo/' BEGIN {print a}'
foo

Sin awkembargo, todos funcionan igual para secuencias de escape válidas:

$ a='\\-\b' awk 'BEGIN {print ENVIRON["a"]}' | od -tc
0000000   \   \   -   \   b  \n
0000006

(contenido de $aaprobado tal cual)

$ awk -v a='\\-\b' 'BEGIN {print a}' | od -tc
0000000   \   -  \b  \n
0000004

( \\cambiado \y \bcambiado a un carácter de retroceso).


¿Estás diciendo que si el patrón fuera, por ejemplo, \d{3}encontrar tres dígitos, eso no funcionaría como se esperaba si te entendiera bien?
branquito

2
para lo \dcual no es una secuencia de escape C válida, eso depende de su awkimplementación (ejecutar awk -v 'a=\d{3}' 'BEGIN{print a}'para verificar). Pero para \` or \ b , yes definitely. (BTW, I don't know of any awk implementations that understands \ d` como significado de un dígito).
Stéphane Chazelas

dice: advertencia awk - secuencia de escape \d' treated as plain d 'd {3}, así que supongo que tendría un problema en este caso?
branquito

1
Lo siento, mi mal, tuve un error tipográfico en mi respuesta. El nombre de la variable de entorno debe coincidir ENVIRON["PATTERN"]con la PATTERNvariable de entorno. Si desea usar una variable de shell, primero debe exportarla ( export variable) o usar la ENV=VALUE awk '...ENVIRON["ENV"]'sintaxis de paso env-var como en mi respuesta.
Stéphane Chazelas

1
Porque necesita exportar una variable de shell para que se pase en el entorno a un comando.
Stéphane Chazelas

5

Intenta algo como:

awk -v l="$line" -v search="$pattern" 'BEGIN {p=0}; { if ( match( $0, search )) {p=1}}; END{ if(p) print l >> "outfile.txt" }'

Si esto se comporta igual que /regex/en términos de búsqueda de patrones, esta podría ser una buena solución. Intentaré.
branquito

1
Las pruebas rápidas que realicé parecían funcionar igual, pero ni siquiera comenzaré a garantizarlo ... :)
Hunter Eidson

0

No, pero puede simplemente interpolar el patrón en la cadena de comillas dobles que pasa a awk:

awk -v l="$line" "BEGIN {p=0}; /$pattern/ {p=1}; END{ if(p) print l >> \"outfile.txt\" }"

Tenga en cuenta que ahora tiene que escapar del literal awk entre comillas dobles, pero sigue siendo la forma más sencilla de lograr esto.


Es seguro de esta manera si $patterncontiene espacios, mi ejemplo de arriba funcionará ya que $ 1 está protegido con comillas dobles "$ 1", sin embargo, no sé qué sucede en su caso.
branquito

2
Su ejemplo original finaliza la cadena de comillas simples en la segunda ', luego protege las $1comillas dobles y luego agrega otra cadena de comillas simples para la segunda mitad del programa awk. Si lo entiendo correctamente, esto debería tener exactamente el mismo efecto que proteger a $1través de las comillas simples externas: awk nunca ve las comillas dobles que coloca a su alrededor.
Kilian Foth

44
Pero si $patterncontiene ^/ {system("rm -rf /")};, entonces estás en un gran problema.
Stéphane Chazelas

¿Es ese el único inconveniente de este enfoque, ya que todo está envuelto en ""?
branquito

-3

Puede usar la función eval que resuelve en este ejemplo la variable nets antes de ejecutar awk.

nets="searchtext"
eval "awk '/"${nets}"/'" file.txt
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.