
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 -v
opció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 = $1
debería ser week="$1"
.
Por cierto,siempre ponga comillas dobles alrededor de las sustituciones de comandos. Por ejemplo, si TOKEN
es *
, sería reemplazado por la lista de archivos en el directorio actual.
awk -v "group=$TOKEN"
Sin embargo , esto no se establece group
en 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 TOKEN
es una cadena de 7 caracteres foo\bar
, entonces la variable awk group
se establece en una cadena de 6 caracteres foo␈ar
donde ␈
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 ENVIRON
matriz.
Además, no está utilizando la variable group
en 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 TOKEN
es GROUP2
entonces un campo que lo contiene GROUP24
no 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 $0
es 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.