AWK: pasar variables de shell a awk

AWK: pasar variables de shell a awk

Estoy tratando de pasar unvariablenúmero de argumentos del script de shell a un subconjunto de reconocimiento de patrones de una tabla. Aquí está mi intento hasta ahora:

El archivo 'archivo':

    ID,GROUP
    1,GROUP2    
    2,GROUP2    
    3,GROUP4    
    4,GROUP4    
    5,GROUP5    
    6,GROUP5    
    7,GROUP23   
    8,GROUP23   
    9,GROUP23   

El archivo subconjunto.sh:

    #!/bin/sh
    rm -f outfile_$week

    week = $1
    shift

    for TOKEN in "$@"
    do

    echo "adding records for" $TOKEN

    awk -F "," -v group = $TOKEN '{ if(FNR > 2 && $2 ~/group/){print $0} }' infile >> outfile_$week
    done

También probé group = "$TOKEN", "group = $TOKEN" y luego ambos con comillas simples. Estoy enviando así:

    sh subset.sh 061314 GROUP2 GROUP23

El error que recibo es sorprendentemente poco informativo.

    Usage: awk [-F fs][-v Assignment][-f Progfile|Program][Assignment|File] ...

Cualquier ayuda es muy apreciada, ¡gracias!

EDITAR: Intenté ejecutar

    awk -F "," -v group ="GROUP1" '{ if(FNR > 2 && $2 ~/group/){print $0} }' infile

Fue en vano... (mismo error que el anterior). ¿Alguien sabe alguna razón por la que esto podría suceder?

Respuesta1

Deberías escribir:

-v group="$TOKEN"

en lugar de -v group = $TOKEN, lo que provoca un error de sintaxis en awk.

Respuesta2

Suena como si quisieras:

awk -F, '
  BEGIN {
    for (i = 1; i < ARGC; i++) group[ARGV[i]]
    ARGC=0
  }
  NR >= 2 && $2 in group' "$@" < infile

O si realmente desea considerar los argumentos como expresiones regulares para compararlos con la segunda columna:

awk -F, '
  BEGIN {
    for (i = 1; i < ARGC; i++) group[ARGV[i]]
    ARGC=0
  }
  NR >= 2 {
    for (i in group) if ($2 ~ i) {print; next}
  }' "$@" < infile

Respuesta3

Su problema inmediato son los espacios alrededor del signo igual. El argumento de la -vopción debe ser una tarea. Awk ve un argumento para -v, seguido de un script ( =), seguido de nombres de archivos (el valor de TOKEN, su script y sus nombres de archivos).

Cometiste un error similar en el script de shell más arriba: week = $1debería ser week="$1".

Por cierto,siempre ponga comillas dobles alrededor de las sustituciones de comandos. Por ejemplo, si TOKENes *, sería reemplazado por la lista de archivos en el directorio actual.

awk -v "group=$TOKEN"

Sin embargo , esto no se establece groupen el valor de TOKEN, porque awk trata el lado derecho de la asignación como un literal en la sintaxis de awk. Por ejemplo, si el valor de TOKENes una cadena de 7 caracteres foo\bar, entonces la variable awk groupse establece en una cadena de 6 caracteres foo␈ardonde hay un carácter de retroceso (valor de byte 8).

La forma sencilla de pasar una variable a un script awk es exportarla al entorno y utilizarla a través de la ENVIRONmatriz.

Además, no está utilizando la variable groupen ninguna parte del script awk. La expresión regular /group/coincide con cualquier cadena que contenga la cadena de 5 caracteres group. Si desea comprobar si el campo es exactamente el valor de group(de modo que, por ejemplo, si el valor de TOKENes GROUP2entonces un campo que lo contiene GROUP24no coincidirá), utilice el operador de igualdad ==.

  export TOKEN
  awk -F "," '{ if (FNR > 2 && $2 == ENVIRON["TOKEN"]){print $0} }' infile >> outfile_$week

Aquí está el script completo, simplificado un poco más para usar la sintaxis condición-acción de awk (donde la acción se omite aquí ya que print $0es la opción predeterminada) y para evitar abrir el archivo de salida cada vez:

#!/bin/sh
week="$1"
shift
for TOKEN in "$@"
do
  echo "adding records for" $TOKEN
  awk -F "," 'FNR > 2 && $2 == ENVIRON["TOKEN"]' infile 
done >"outfile_$week"

VerLa respuesta de Stéphane Chazelaspara obtener una forma más avanzada de utilizar awk que no requiera procesar el archivo de entrada varias veces.

información relacionada