awk com instruções if

8

Estou tentando imprimir de um arquivo usando o awk, mas minha saída está vazia. Aqui esta o meu codigo ate agora

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

Eu também tentei isso:

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

O arquivo de entrada é:

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

A saída esperada quando executo o arquivo é

$./file.sh 3
Will Smith

Mas eu recebo o seguinte

$./file.sh 3
$

Isso não está sendo impresso. Conheço a solução com cut, mas quero usar o awk.

gkmohit
fonte

Respostas:

8

Você deve usar a -vopção de awk:

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

Com $1aspas duplas, o shell manipulará todos os seus caracteres especiais (se houver) para você.

cuonglm
fonte
3

Você tem:

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

Como a variável shell accountNumentra awk? Não precisa: você precisa fornecer seu valor awkexplicitamente. Você pode usar:

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

que deixa aspas simples e faz com que o shell substitua o valor de sua variável no awkcomando, depois reinsere aspas simples para o restante da cadeia de comandos.

Um script melhor ou pelo menos mais idiomático seria:

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

que lida com números de conta não numéricos (citando a variável substituída), usa um bloco de padrão em vez de um explícito if(o {}bloco será executado se o teste for verdadeiro) e imprime um espaço entre os nomes conforme desejado (por causa de ,) Se você preferir usar ifexplicitamente, mova o teste para dentro do seuif declaração .

Dependendo do seu objetivo real, awkpode não ser o melhor ajuste para o que você está fazendo. O texto acima ainda falha se o script $1tiver aspas. O loop de shell que você tinha não estava fazendo nada útil, embora repetisse a saída várias vezes.

Michael Homer
fonte
você está dizendo que eu deveria remover o whileloop? :)
gkmohit
Pelo menos para os exemplos, não está fazendo nada para ajudá-lo.
Michael Homer
3

Seu script já faz praticamente o trabalho sem nenhum awk:

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

Não estou sugerindo que essa seja uma solução melhor ou mais eficiente do que usar awksozinha, mas se você deseja o while...readloop, isso certamente supera awkprocessos separados por cada linha. Apenas uma FYI, eu acho.

mikeserv
fonte
Não apenas um awk para cada linha, mas esse awk lê o arquivo inteiro novamente para cada linha que o próprio shell lê. Maneira de obter um algoritmo O (n ^ 2).
Paul_Pedant
1
#!/bin/bash

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

Com a -v a="$1"definição da awkvariável ano valor do primeiro argumento de linha de comando do script, especificamos que a entrada é separada por vírgula -F ','. Se a primeira coluna for igual ao valor de a, imprima as duas outras colunas na ordem inversa.

Você não obtém nada em sua saída ao comparar a primeira coluna com a awkvariável accountNum, que não está definida.

Se houvesse uma entrada cuja primeira coluna tivesse 0 (zero) nela, essa entrada teria sido impressa. Isso ocorre porque o valor das variáveis ​​não definidas em é awkavaliado como zero.

Kusalananda
fonte