awk avec des instructions if

8

J'essaie d'imprimer à partir d'un fichier en utilisant awk, mais ma sortie est vide. Voici mon code jusqu'à présent

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

J'ai également essayé ceci:

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

Le fichier d'entrée est:

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

La sortie attendue lorsque j'exécute le fichier est

$./file.sh 3
Will Smith

Mais je reçois ce qui suit

$./file.sh 3
$

Ce n'est rien qui est imprimé. Je connais la solution avec cut, mais je veux utiliser awk.

gkmohit
la source

Réponses:

8

Vous devez utiliser l' -voption de awk:

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

Avec $1des guillemets doubles, le shell gérera tout son caractère spécial (si a) pour vous.

cuonglm
la source
3

Vous avez:

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

Comment la variable shell accountNumentre- awkt-elle? Ce n'est pas le cas: vous devez fournir sa valeur awkexplicitement. Vous pouvez utiliser:

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

qui laisse des guillemets simples et a le shell substituer la valeur de sa variable dans la awkcommande, puis réentre des guillemets simples pour le reste de la chaîne de commande.

Un script meilleur ou au moins plus idiomatique serait:

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

qui traite des numéros de compte non numériques (en citant la variable substituée), utilise un bloc de modèle au lieu d'un explicite if(le {}bloc s'exécutera si le test avant qu'il soit vrai) et imprime un espace entre les noms comme vous le vouliez (en raison de ,). Si vous préférez utiliser ifexplicitement, déplacez le test dans votre ifinstruction existante .

Dépendre de votre objectif réel awkn'est peut-être pas le mieux adapté à ce que vous faites. Ce qui précède échoue toujours si le script $1contient des guillemets. La boucle shell que vous aviez ne faisait rien d'utile, même si elle aurait répété la sortie plusieurs fois.

Michael Homer
la source
dites-vous que je devrais supprimer la whileboucle? :)
gkmohit
Au moins pour les exemples, il ne fait rien pour vous aider.
Michael Homer
3

Votre script fait déjà pratiquement le travail sans aucun awk:

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

Je ne dis pas que c'est une solution meilleure ou plus efficace que l'utilisation awkseule, mais si vous voulez la while...readboucle, cela bat certainement des awkprocessus distincts pour chaque ligne. Juste un FYI, je suppose.

mikeserv
la source
Pas seulement un awk pour chaque ligne, mais cet awk lit à nouveau le fichier entier pour chaque ligne que le shell lui-même lit. Façon d'obtenir un algorithme O (n ^ 2).
Paul_Pedant
1
#!/bin/bash

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

Avec -v a="$1"nous définissons la awkvariable asur la valeur du premier argument de ligne de commande du script, nous spécifions alors que l'entrée est séparée par des virgules -F ','. Si la première colonne est égale à la valeur de a, imprimez les deux autres colonnes dans l'ordre inverse.

Vous n'obtenez rien dans votre sortie lorsque vous comparez la première colonne à la awkvariable accountNum, qui n'est pas définie.

S'il y avait eu une entrée dont la première colonne avait 0 (zéro), cette entrée aurait été imprimée. En effet, la valeur des variables non définies dans est awkévaluée à zéro.

Kusalananda
la source