awk con declaraciones if

8

Estoy tratando de imprimir desde un archivo usando awk, pero mi salida está vacía. Aquí está mi código hasta ahora

accountNum=$1
while read -r LINE || [[ -n $LINE ]] ; do
            awk -F',' '{ if($1==accountNum) { print $3.$2 } }' Accounts
done < Accounts

También he intentado esto:

accountNum=$1
while read -r LINE || [[ -n $LINE ]] ; do
            echo $LINE  | awk -F',' '{ if($1==accountNum) { print $3.$2 } }' 
done < Accounts

El archivo de entrada es:

1,Doe,John
2,Rooney,Wayne
3,Smith,Will
4,Crow,Russel
5,Cruise,Tom

El resultado esperado cuando ejecuto el archivo es

$./file.sh 3
Will Smith

Pero me sale lo siguiente

$./file.sh 3
$

Eso es nada se está imprimiendo. Conozco la solución con corte, pero quiero usar awk.

gkmohit
fuente

Respuestas:

8

Debe usar la -vopción de awk:

awk -F',' -v accNum="$1" '$1 == accNum {print $3,$2}'

Con $1comillas dobles, el shell manejará todos sus caracteres especiales (si los tiene) para usted.

Cuonglm
fuente
3

Tienes:

accountNum=$1
awk -F',' '{ if($1==accountNum) { print $3.$2 } }' Accounts

¿Cómo funciona la variable de shell accountNumentrar en awk? No lo hace: debe proporcionar su valor awkexplícitamente. Puedes usar:

awk -F',' '{ if($1=='"$accountNum"') { print $3.$2 } }' Accounts

que deja comillas simples y hace que el shell sustituya el valor de su variable en el awkcomando, luego vuelve a ingresar comillas simples para el resto de la cadena de comandos.

Un guión mejor o al menos más idiomático sería:

#!/bin/sh
accountNum=$1
awk -F, '$1 == "'"$accountNum"'" { print $3,$2 }' Accounts

que trata con números de cuenta no numéricos (citando la variable sustituida), usa un bloque de patrón en lugar de un explícito if(el {}bloque se ejecutará si la prueba antes es verdadera) e imprime un espacio entre los nombres como deseaba (debido a ,) Si prefiere usarlo ifexplícitamente, mueva la prueba dentro de su ifdeclaración existente .

Dependiendo de su objetivo real awkpuede no ser la mejor opción para lo que está haciendo. Lo anterior sigue fallando si el script $1tiene comillas. El bucle de shell que tenía no estaba haciendo nada útil, aunque habría repetido la salida muchas veces.

Michael Homer
fuente
¿Estás diciendo que debería eliminar el whilebucle? :)
gkmohit
Al menos para los ejemplos, no está haciendo nada para ayudarte.
Michael Homer
3

Su script ya hace prácticamente el trabajo sin ninguno awk:

while IFS=, read -r num last first
    do  [ $((num==accountNum)) -eq 1 ] && 
        printf '%s.%s\n' "$first" "$last"
done < Accounts

No estoy sugiriendo que esta sea una solución mejor o más eficiente que usarla awksola, pero si desea el while...readciclo, esto ciertamente supera awkprocesos separados por cada línea. Solo un FYI, supongo.

mikeserv
fuente
No solo un awk para cada línea, sino que ese awk lee todo el archivo nuevamente para cada línea que lee el propio shell. Manera de obtener un algoritmo O (n ^ 2).
Paul_Pedant
1
#!/bin/bash

awk -v a="$1" -F ',' '$1 == a { print $3, $2 }' Accounts

Con -v a="$1"establecemos la awkvariable aen el valor del primer argumento de línea de comando del script, luego especificamos que la entrada está separada por comas -F ','. Si la primera columna es igual al valor de a, imprima las otras dos columnas en orden inverso.

No obtiene nada en su salida al comparar la primera columna con la awkvariable accountNum, que no está configurada.

Si hubiera habido una entrada cuya primera columna tuviera 0 (cero), esa entrada se habría impreso. Esto se debe a que el valor de las variables no definidas en se awkevalúa a cero.

Kusalananda
fuente