#1 Le 16/12/2019, à 17:51
- Oliv83200
Enregistrer commande dans variable dans awk
Bonjour,
Je tente par tout moyen de constituer un fichier avec le nom de plusieurs VMs à partir de leur adresse ip qui se trouve dans la colonne 3 d'un fichier csv source. Pour cela j'interroge une base sur laquelle se trouve une table de correspondance.
Je m'y prends donc par script bash de la façon suivante:
#!/bin/bash
for machine in /usr/src/fichier.csv
do
awk -F";" '
BEGIN{OFS=";";print "vm"}
{testip=$(eval "mysql -h 128.10.10.10 -u toto -pPassword -B --execute=\"SELECT name FROM ecs WHERE ipaddress='$3'\" | tail -n1")
print $testip}
' $machine > /home/oliv83200/nommachine.csv
done
exit 0
La commande se trouvant dans la variable fonctionne (je l'ai testé dans ma console, c'est ok).
Mais quand j’exécute mon script et que je vais aux résultats, je constate qu'il interprète ma variable $testip comme un $0 puisqu'il m'affiche la totalité des colonnes du fichier initial.
Est ce awk qui n'accepte pas la forme $var=$(ma commande)?
Avez vous une solution.
En vous remerciant.
Hors ligne
#2 Le 16/12/2019, à 18:20
- kamaris
Re : Enregistrer commande dans variable dans awk
Ton montage est à revoir : la boucle for ne sert à rien (et ne fait peut-être pas ce que tu penses), et tu mets du bash dans du awk.
Voici une manière de faire : d'abord tu récupères tes ips dans un tableau :
mapfile -t a < <(awk -F';' '{print $3}' /usr/src/fichier.csv)
Ensuite, tu boucles sur les éléments de ce tableau pour les passer en argument à ta commande mysql, et renseigner en sortie le second fichier :
for ip in "${a[@]}"; do
mysql -h 128.10.10.10 -u toto -pPassword -B --execute="SELECT name FROM ecs WHERE ipaddress='$ip'" | tail -n1
done > /home/oliv83200/nommachine.csv
Hors ligne
#3 Le 17/12/2019, à 09:02
- Oliv83200
Re : Enregistrer commande dans variable dans awk
Merci Kamaris,
Je faisais appel à la boucle for car je récupère d'autres valeurs dans le fichier csv initial (j'ai dépouiillé mon code pour le rendre plus clair sur le forum).
en fait je fais quelque chose de ce type:
{testip=$(eval "mysql -h 128.10.10.10 -u toto -pPassword -B --execute=\"SELECT name FROM ecs WHERE ipaddress='$3'\" | tail -n1")
print $3$2,$2,$testip}
Je ne comprends pas la variable ${a[@]} dans ton code.
Cordialement,
Olivier
Hors ligne
#4 Le 17/12/2019, à 13:12
- kamaris
Re : Enregistrer commande dans variable dans awk
Quel que soit le traitement réalisé sur le fichier /usr/src/fichier.csv, la boucle for est inutile, car elle ne fait qu'affecter la valeur « /usr/src/fichier.csv » à la variable « machine ».
Pour t'en convaincre, tu peux faire
for machine in /usr/src/fichier.csv; do
echo "'$machine'"
done
Une boucle for ne lit pas un fichier, elle ne lit que ce que tu lui mets comme mots entre le « in » et le « ; » ou la fin de ligne qui suit.
Ici, elle ne lit donc que la chaine de caractères « /usr/src/fichier.csv ».
Si tu veux lire un fichier en bash, il faut utiliser une boucle while et la commande read :
while IFS='' read -r line; do
…
done < fichier
Mais ici c'est inutile : à partir du moment où tu utilises awk, c'est lui qui se chargera de lire le fichier.
Ensuite, étant donné ce que tu veux faire, peut-être qu'effectivement les appels système depuis awk se justifient, mais il ne faut pas les faire comme ça.
Et il ne faut pas utiliser eval, d'ailleurs inutile ici.
Tu peux faire comme ça :
awk -F';' '{ print "vm"; printf "%s%s;%s;" $3, $2, $2; system("mysql -h 128.10.10.10 -u toto -pPassword -B --execute=\"SELECT name FROM ecs WHERE ipaddress='" $3 "'\" | tail -n1")}' /usr/src/fichier.csv > /home/oliv83200/nommachine.csv
Attention à bien arrêter puis reprendre les guillemets doubles pour que le « $3 » soit interprété comme le troisième champ awk, et non pas comme le troisième paramètre de position du shell qui exécute la commande mysql.
Enfin, en ce qui concerne "${a[@]}", il s'agit du développement des éléments du tableau « a » en mots séparés :
If the word is double-quoted, ${name[*]} expands to a single word with the value of each array member separated by the first character of the IFS special variable, and ${name[@]} expands each element of name to a separate word.
Pour essayer de voir un peu comment ça fonctionne, tu peux faire l'expérience suivante : tu définis un tableau « a » par
a=(a b 'a b')
Puis tu affiches ses éléments à l'aide des boucle for suivantes, et tu observes le résultat :
for w in "${a[@]}"; do echo "'$w'"; done
for w in ${a[@]}; do echo "'$w'"; done
for w in "${a[*]}"; do echo "'$w'"; done
for w in ${a[*]}; do echo "'$w'"; done
Dernière modification par kamaris (Le 17/12/2019, à 13:17)
Hors ligne
#5 Le 17/12/2019, à 15:30
- Oliv83200
Re : Enregistrer commande dans variable dans awk
Merci kamaris pour ton aide et ta pédagogie,
Je comprends mes erreurs.
Néanmoins je suis toujours bloqué sur un soucis de synthax dans la commande system()
Pour me faciliter la chiose, j'ai remplacé la variable $3 par une adresse ip connu de ma base.
Lorsque je rentre ma commande de cette manière:
awk -F';' '{ print "vm"; printf "%s%s;%s;" $3, $2, $2; system("mysql -h 128.10.10.10 -u toto -pPassword -B --execute="SELECT name FROM ecs WHERE ipaddress='128.10.10.10'" | tail -n1")}' /usr/src/fichier.csv > /home/oliv83200/nommachine.csv
il m'affiche "awk: 2: unexpected character '.'
Et lorsque je rentre la commande de cette manière (en mettant des \ avant les quote et double quotes qu'il ne doit pas tenir compte):
awk -F';' '{ print "vm"; printf "%s%s;%s;" $3, $2, $2; system("mysql -h 128.10.10.10 -u toto -pPassword -B --execute=\"SELECT name FROM ecs WHERE ipaddress='\128.10.10.10\'\" | tail -n1")}' /usr/src/fichier.csv > /home/oliv83200/nommachine.csv
il m'affiche :
"./testip.sh: ligne 3: fin de fichier (EOF) prématurée lors de la recherche du « " » correspondant
./testip.sh: ligne 6: erreur de syntaxe : fin de fichier prématurée"
je viens de me lire le man de system(), tester d'autre synthax etc, je ne trouve pas la solution.
Hors ligne
#6 Le 17/12/2019, à 15:49
- kamaris
Re : Enregistrer commande dans variable dans awk
Ah oui, c'est à cause des guillemets simples qui sont interprétés comme terminant le programme awk, et non comme partie intégrante de ce qu'il doit afficher.
Il faut les concaténer avec le reste du programme awk en utilisant le mécanisme d'échappement des caractères spéciaux de bash :
awk -F';' '{ print "vm"; printf "%s%s;%s;" $3, $2, $2; system("mysql -h 128.10.10.10 -u toto -pPassword -B --execute=\"SELECT name FROM ecs WHERE ipaddress='\''" $3 "'\''\" | tail -n1")}' /usr/src/fichier.csv > /home/oliv83200/nommachine.csv
---
Sinon, si tu veux éviter d'alterner les guillemets simples / doubles avec ou sans anti-slash, tu peux passer à awk des variables contenant ces guillemets et les utiliser ensuite en interne :
awk -F';' -v g1=\' -v g2=\" '{ print "vm"; printf "%s%s;%s;" $3, $2, $2; system("mysql -h 128.10.10.10 -u toto -pPassword -B --execute=" g2 "SELECT name FROM ecs WHERE ipaddress=" g1 $3 g1 g2 " | tail -n1")}' /usr/src/fichier.csv > /home/oliv83200/nommachine.csv
Je te laisse tester, mais ces deux formulations doivent être équivalentes.
Dernière modification par kamaris (Le 17/12/2019, à 17:17)
Hors ligne
#7 Le 17/12/2019, à 17:41
- Oliv83200
Re : Enregistrer commande dans variable dans awk
Effectivement de cette manière ça fonctionne.
Pas simple de s'y retrouver dans les quotes et doubles interprété ou non. La technique de les enregistrer dans une variable est intéressante.
Bizarrement la commande system(mysql) me sort mon resultat suivi d'un zéro à la ligne:
resultat 1
0
resultat2
0
resultat3
0
...
J'ai beau modifié mont tail -n1, ce 0 venu de nul part (pas dans la base) reste.
Hors ligne
#8 Le 17/12/2019, à 17:47
- pingouinux
Re : Enregistrer commande dans variable dans awk
Bonjour,
Bizarrement la commande system(mysql) me sort mon resultat suivi d'un zéro à la ligne:
C'est le code de retour de la commande.
system(cmd-line) Execute the command cmd-line, and return the exit status. (This may not be
available on non-POSIX systems.)
Hors ligne
#9 Le 17/12/2019, à 20:12
- kamaris
Re : Enregistrer commande dans variable dans awk
Je ne sais pas pourquoi le code de retour de la commande vient parasiter la sortie.
Chez moi j'ai par exemple
$ echo | awk '{system("echo ok")}'
ok
$
alors que echo renvoie bien aussi 0 comme code de retour.
Mais tu dois pouvoir virer ce zéro en le mettant dans une variable poubelle :
$ echo | awk '{trash=system("echo ok")}'
ok
$
Hors ligne
#10 Le 17/12/2019, à 20:27
- pingouinux
Re : Enregistrer commande dans variable dans awk
En effet, c'est curieux. J'avoue que j'avais consulté le man, mais sans faire le test.
Hors ligne
#11 Le 17/12/2019, à 21:24
- Watael
Re : Enregistrer commande dans variable dans awk
mais, il y a un gain, ici, à utiliser awk avec un appel system(), plutôt qu'une lecture du fichier en shell, et l'exécution des requêtes sql dans le même contexte ?
Connected \o/
Welcome to sHell. · eval is evil.
En ligne
#12 Le 17/12/2019, à 21:57
- kamaris
Re : Enregistrer commande dans variable dans awk
Un gain je sais pas, mais disons que c'est une possibilité.
Au départ (en #2) j'avais plutôt choisi d'esquiver ça, mais comme ensuite Oliv83200 a rajouté des manipulations de champs en #3, je me suis dit pourquoi pas tout faire dans awk effectivement.
Hors ligne
#13 Le 17/12/2019, à 22:17
- Watael
Re : Enregistrer commande dans variable dans awk
ça me paraît tortueux (matrïochka-esque) :
un script shell qui exécute une commande awk, qui exécute une commande shell. 8O
Connected \o/
Welcome to sHell. · eval is evil.
En ligne
#14 Le 17/12/2019, à 22:32
- kamaris
Re : Enregistrer commande dans variable dans awk
Da!
Mais par contre, la commande donnée #6 est censée se suffire à elle-même : plus de script shell au-dessus.
Hors ligne
#15 Le 17/12/2019, à 22:44
- Watael
Re : Enregistrer commande dans variable dans awk
plus de script shell au-dessus
alors, tu l'exécutes où la commande awk ?
Connected \o/
Welcome to sHell. · eval is evil.
En ligne
#16 Le 17/12/2019, à 23:43
- kamaris
Re : Enregistrer commande dans variable dans awk
Ben dans un terminal.
Oui je sais, ça reste un shell, mais ce que je veux dire c'est qu'elle remplace tout le script en #1.
Hors ligne
#17 Le 18/12/2019, à 00:20
- Watael
Re : Enregistrer commande dans variable dans awk
tout le script consistait en une boucle for erronée.
reste un script shell, qui exécute awk, qui exécute un shell.
autant faire un simple shell, comme tu le faisais en #2.
KISS.
Connected \o/
Welcome to sHell. · eval is evil.
En ligne
#18 Le 18/12/2019, à 10:46
- Oliv83200
Re : Enregistrer commande dans variable dans awk
Encore merci pour l'aide que vous m'apportez.
J'ai tenté de faire comme en #2 mais je suis bloqué par la suite pour récupérer les autres valeurs de mon csv que je dois afficher dans le même tableau que le nom de mes machines.
De même quand je reproduis exactement le awk en #6 , j'ai le droit à cette erreur:
awk: run time error: not enough arguments passed to printf("%s%s;%s;128.15.15.15")
FILENAME="/usr/src/fichier.csv" FNR=1 NR=1
Je l'ai donc modifié comme tel:
awk -F";" 'BEGIN{OFS=";";print ""vm"}{ print $3$2,$2,system("mysql -h 128.10.10.10 -u toto -pPassword -B --execute=\"SELECT name FROM ecs WHERE ipaddress='\''" $3 "'\''\" | tail -n1")}' /usr/src/fichier.csv > /home/oliv83200/nommachine.csv
j'ai donc rencontré le problème de 0 ajouté au résultat de la commande mysql. Qui serait donc le code retour de system().
Lorsque je modifie le code de cette manière:$
awk -F";" 'BEGIN{OFS=";";print ""vm"}{ trash=system("mysql -h 128.10.10.10 -u toto -pPassword -B --execute=\"SELECT name FROM ecs WHERE ipaddress='\''" $3 "'\''\" | tail -n1"); print $3$2,$2,trash}' /usr/src/fichier.csv > /home/oliv83200/nommachine.csv
Ca ne change rien, le 0 est toujours présent dans mon résultat.
Hors ligne
#19 Le 18/12/2019, à 12:00
- Oliv83200
Re : Enregistrer commande dans variable dans awk
C'est bon!
J'arrive au résultat souhaité en reprenant #6 comme tel:
awk -F';' 'BEGIN{OFS=";";print "vm"}{printf "%s%s;%s;", $3, $2, $2; system("mysql -h 128.10.10.10 -u toto -pPassword -B --execute=\"SELECT name FROM ecs WHERE ipaddress='\''" $3 "'\''\" | tail -n1")}' /usr/src/fichier.csv > /home/oliv83200/nommachine.csv
Un grand merci pour votre aide !
Merci, merci, merci!
Hors ligne
#20 Le 18/12/2019, à 12:56
- kamaris
Re : Enregistrer commande dans variable dans awk
Arf ! Oui, j'avais oublié une virgule !
C'est le problème quand on ne teste pas bien en local, désolé.
Tu ne dois pas avoir besoin du OFS=";" je crois, mais bon, c'est pas bien grave.
Pour faire « comme en #2 », ou plutôt substituer bash à awk, il aurait fallu que tu utilises la boucle while dont je t'ai parlé en #4 pour lire un fichier, en l'adaptant un peu :
while IFS=';' read -r champ1 champ2 champ3 ligne; do
…
done < /usr/src/fichier.csv > /home/oliv83200/nommachine.csv
Je te laisse compléter l'intérieur de la boucle si ça te dit
Hors ligne
#21 Le 18/12/2019, à 12:59
- Watael
Re : Enregistrer commande dans variable dans awk
J'ai tenté de faire comme en #2 mais je suis bloqué par la suite pour récupérer les autres valeurs de mon csv que je dois afficher dans le même tableau que le nom de mes machines.
donne-nous une exemple représentatif du fichier, la sortie attendue correspondante, et une petite explication si la transformation n'est pas évidente
ça n'a pas l'air bien compliqué, il n'y a pas de raison que ce ne soit pas simplissime en shell.
Connected \o/
Welcome to sHell. · eval is evil.
En ligne