IFS : séparateurs & scripts BASH

Un truc qui m’a pris la tête il fût un temps et plus récemment, pour une question de syntaxe oubliée.
Voilà le topo : vous faites un rapide script BASH pour faire tel ou tel traitement sur des fichiers. Et là, chaque espace dans un nom de fichier vous met en l’air votre script car c’est vu comme “un saut de ligne”, dirons-nous.
Il faut alors penser à jouer avec le “Internal Field Separator” – IFS – pour indiquer à BASH quel(s) caractère(s) considérer comme saut de ligne.
Par défaut, on trouve le saut de ligne “ ”, mais aussi la tabulation (” ”) et l’espace !!!

Simplification possible du problème : un extrêmiste pinguiste vous dira simplement que les espaces dans un nom de fichier, c’est mal. Ca a beau être mal, qui n’a jamais collé un espace dans un nom de fichier ? qui a le choix de ne pas le faire ? ou de tuer ses gentils utilisateurs le faisant ?

En images, ça donne ça :

user@srv:/tmp$ echo >> liste
champ1.1;champ1.2;champ1.3
champ2.1;champ avec espace;champ2.3
champ   avec_tabulation;champ3.2;champ pour finir
CTRL-D pour finir la saisie

user@srv:/tmp$ for i in `cat liste`
> do
> echo $i
> done
champ1.1;champ1.2;champ1.3
champ2.1;champ
avec
espace;champ2.3
champ
avec_tabulation;champ3.2;champ
pour
finir

Houuu le vilain résultat pour quelqu’un qui voulait voir afficher 3 lignes, pour par exemple faire un “awk -F ‘;’ ‘{print $1 ou $2 ou $3}’ pour récupérer tel ou tel champ d’un fichier CSV.
Notez que le “$i” ne changera rien par rapport au $i.

Solution : redéfinir l’IFS.
D’abord le on le sauvegarde car c’est pas simple de taper son contenu, la preuve, affichez cette variable, elle semble vide :

user@srv:/tmp$ echo $IFS

user@srv:/tmp$

La difficulté de syntaxe mentionnée au début de l’article est de faire gober le “ ” sans interprétation par le shell, voici comment faire dans le cas qui nous intéresse : (le reste est expliqué sur wikipedia)

user@srv: /tmp$ OLDIFS=$IFS
user@srv:/tmp$ IFS=$'
'
user@srv:/tmp$ for i in `cat liste`; do echo "$i"; done
champ1.1;champ1.2;champ1.3
champ2.1;champ avec espace;champ2.3
champ   avec_tabulation;champ3.2;champ pour finir

A noter que votre variable IFS restera en l’état pendant toute votre session (ie, votre shell ouvert). Donc n’oubliez pas de rétablir IFS=$OLDIFS.
Si vous faites ceci dans un script, c’est alors propre à l’exécution du script.

Enfin, pour les bidouilleux, ça peut permettra de faire du découpage assez bizzarement :

user@srv:/tmp$ IFS=a
user@srv:/tmp$ for i in `cat liste`; do echo "$i"; done
ch
mp1.1;ch
mp1.2;ch
mp1.3
ch
mp2.1;ch
mp
vec esp
ce;ch
mp2.3
ch
mp
vec_t
bul
tion;ch
mp3.2;ch
mp pour finir
Vus : 391
Publié par Michauko : 64