Je souhaite améliorer un script bash existant. Le principal problème est qu'il utilise n fois une même commande genre mysql -u <login> -p<mdp> -B -N. Il n'y a que le -e <ma_requête_SQL> qui change entre chaque commande.
J'ai justement un argument à changer… dans chaque appel à la commande. Bon, un coup de sed et le travail est fait, mais je me dis que je vais factoriser tout ça.
Je crée une variable MYSQLCMD='/usr/bin/mysql -B -N -u <login> -p<mdp>' et je remplace toutes les commandes de la forme mysql -u <login> […] -e "ma_requête_SQL> par $MYSQLCMD -e ma_requête_SQL>.
Je teste… Ça fonctionne partout… sauf à plusieurs endroits du script. L'erreur est : « mon_script.sh: ligne 138: /usr/bin/mysql -B -N -u root -p<CENSURÉ>: Aucun fichier ou dossier de ce type ». On dirait que bash cherche une commande qui se nomme « /usr/bin/mysql -B -N -u root -p<CENSURÉ> » (espaces incluses). La commande /usr/bin/mysql existe, mais pas une commande /usr/bin/mysql -B -N -u root -p<CENSURÉ> puisqu'il s'agit d'un mélange d'une commande, de ses arguments et des valeurs de ses arguments.
set -x affiche + '/usr/bin/mysql -B -N -u root -p<CENSURÉ>' -e 'SHOW DATABASES;'. On constate que la variable $MYSQLCMD est développée comme un seul tenant… alors que sa valeur est assignée à l'aide de simples quotes, et non de guillemets. Et, surtout, ce comportement se produit uniquement à partir d'un certain endroit dans le script. Dit autrement, un $MYSQLCMD -e ma_requête_SQL> en début ou en milieu de script fonctionne très bien.
Solution : un bout de code traînait. Un bout de code tout simple :
IFS='
'
Ainsi, le séparateur des champs a été modifié. Sa valeur est passé de espace + tab + line feed à juste line feed (saut de ligne). Évidemment, cela a été fait dans une intention bien précise : itérer sur chaque ligne d'un résultat d'une requête SQL avec une boucle for… Illustration :
IFS='
'
for line in $(mysql -B -N -u <login> -p<mdp> -D <base> -e <requête_sql) do
[travail sur $line]
done
Sans la modification du séparateur, la boucle itère sur chaque colonne du résultat au lieu d'itérer sur chaque ligne du résultat.
Évidemment, bidouiller IFS est une mauvaise pratique. Dans ce contexte-là, on préférera utiliser une boucle while read. ;)
Virer cette modification du séparateur résout le problème. \o/