Analyser un fichier texte délimité dans bash comme arguments de commande

10

J'ai un fichier texte divisé comme suit:

field1,field2,field3 
xield1,xield2,xield3 
dield1,dield2,dield3 
gield1,gield2,gield3

Chacune de ces colonnes sera un paramètre d'un programme, et j'aimerais que le programme soit appelé pour chaque ligne

J'espérais une boucle, quelque chose comme:

for $i in file
    command $field2 -x $field3 -PN -$field1 >> output
done

Quelle serait la meilleure façon d'accomplir quelque chose comme ça en bash?

doyen
la source
Le nombre de champs est-il constant?
Joseph R.
@JosephR. oui, ils sont toujours 3
Dean

Réponses:

7
while IFS=, read xx yy zz;do
    echo $xx $yy $zz
done < input_file

Cela devrait fonctionner si le nombre de champs est constant. Au lieu d' echoutiliser votre commande.

coffeMug
la source
Merci, j'essayais juste mais cela ne semble fonctionner que pour la première ligne. Dès qu'une commande réussit, elle n'essaye pas la suivante, si elle échoue, elle essaiera la suivante cependant ...
Dean
Comment entendez-vous par succès ou échec? Que fait votre commande?
coffeMug
Je suppose que la commande qu'il exécute lit l'entrée standard avant que la commande "read" puisse y accéder.
plugwash
4

Vous devez utiliser un whileavec le readintégré:

while IFS= read -r line;do
    fields=($(printf "%s" "$line"|cut -d',' --output-delimiter=' ' -f1-))
    command "${fields[1]}" -x "${fields[2]}" ... # ${fields[1]} is field 2
done < your_file_here

Comment ça marche

  • L' cutinstruction prend la ligne et la divise sur le délimiteur spécifié par -d.
  • C'est --output-delimiterle caractère séparateur qui cutva utiliser pour afficher les champs sélectionnés, ici nous choisissons un espace pour pouvoir mettre les différents champs dans le tableau fields.
  • Enfin, nous voulons tous les champs (du champ 1 à la fin) et c'est là -f1-qu'entre en jeu.
  • Maintenant que les différents champs sont stockés dans la variable de tableau fields, vous pouvez accéder à n'importe quel champ particulier que vous voulez avec la syntaxe ${field[number]}numberest un de moins que le numéro de champ réel que vous souhaitez puisque l'indexation de tableau est basée sur zéro dans Bash.

Remarque

  • Cela échouera si l'un de vos champs contient des espaces.

Pour un nombre constant de champs

Vous pouvez à la place faire quelque chose de similaire à la réponse de 1_CR :

while IFS= read -r line;do
    IFS=, read -r field1 field2 field3 <<-EOI
    $line
    EOI
    command "$field2" -x "$field3" ... 
done < your_file_here

Ce qui précède, tout en semblant plus bruyant, devrait fonctionner dans n'importe quel shell compatible POSIX, pas seulement Bash.

Joseph R.
la source
Ce n'est pas lire le fichier qui me pose problème, c'est casser la ligne en colonnes.
Dean
@Dean Ouais, désolé. Je ne faisais pas attention. J'y travaille maintenant.
Joseph R.
@Dean Veuillez voir la réponse mise à jour. J'ajouterai une explication sous peu.
Joseph R.
@JosephR., Il est possible d'éviter d'utiliser des outils externes pour le fractionnement en définissant IFSune valeur appropriée dans l' readinvocation
iruvar
@ 1_CR Je sais, merci. J'y arrivais juste :)
Joseph R.
1

Vous pouvez arriver readà diviser chaque ligne en un tableau en le ,paramétrant de IFSmanière appropriée.

while IFS=, read -r -a input; do
 printf "%s\n" "${input[0]}" "${input[1]}"
done < input.txt

Ainsi, dans l'exemple ci-dessus, vous pouvez accéder à chaque élément du tableau à l'aide de son index, en commençant à 0.

iruvar
la source
1

Ce awkone-liner fera ce que vous voulez:

awk -F, '{cmd="echo " $2 " -x " $3 " -PN " $1 ">> output";  system(cmd)}' f.txt

Remplacez echopar votre commande et f.txtpar le fichier que vous souhaitez parcourir.

Brève explication: -F,définira ,comme délimiteur. cmdcrée la commande et system(cmd)appelle la commande.

mkc
la source
1

gnu sed peut également être utilisé.

sed infile -e 's!^\([^,]*\),\([^,]*\),\([^,]*\)$!command \1 -x \2 -PN \3!e' >> output

remarquez l'utilisation de l'option e dans la commande s

hildred
la source