$IFS : Le séparateur standard du shell

$IFS pour « Internal Field Separator » est une variable spéciale du shell définissant le « séparateur par défaut », c’est à dire le(s) caractère(s) utilisé(s) pour délimiter les mots dans une chaîne de caractères.

Par défaut, ce séparateur est initialisé à « <espace><tabulation><nouvelle ligne> » (et peut être affiché via la commande ‘echo -n « $IFS » | cat -vTE’).

Concrètement, nous pourrons modifier l’IFS pour simplifier les traitements des noms de fichiers avec espaces dans des boucles, pour implémenter une fonction « split »/ »join » rapidement, etc.

Cet article propose quelques exemples de modification d’IFS courants.

Ré initialisation de l’IFS

Initialiser l’IFS est une simple affectation. Pour ramener le séparateur standard à sa valeur originelle (<espace><tabulation><nouvelle ligne>) nous écririons :

fhh@mafalda ~ $ IFS=$' \t\n'

Noms de fichiers avec espaces

Lors du traitement de noms de fichiers avec espaces dans une boucle par exemple, le résultat n’est pas exactement celui attendu :

fhh@mafalda ~ $ mkdir IFS && cd !$
mkdir IFS && cd IFS/
fhh@mafalda ~/IFS $ mkdir "repertoire avec espace "{1,2} && touch "fichier "{1,2}
fhh@mafalda ~/IFS $ ls -l
total 0
-rw------- 1 fhh users 0 Feb 22 12:03 fichier 1
-rw------- 1 fhh users 0 Feb 22 12:03 fichier 2
drwx------ 2 fhh users 6 Feb 22 12:03 repertoire avec espace 1
drwx------ 2 fhh users 6 Feb 22 12:03 repertoire avec espace 2
fhh@mafalda ~/IFS $ for n in $(ls) ; do echo $n ; done 
fichier
1
fichier
2
repertoire
avec
..

la raison de ce retour est que le séparateur vaut par défaut espace, tabulation ou nouvelle ligne.

Le comportement souhaité est obtenu en modifiant le séparateur par défaut (IFS) :

fhh@mafalda ~/IFS $ IFS=$'\n'; for n in $(ls) ; do echo $n ; done
fichier 1
fichier 2
repertoire avec espace 1
repertoire avec espace 2

Commande split/explode

En jouant sur la valeur d’IFS, nous pouvons implémenter un découpage de chaîne de caractères en fonction d’un motif donné (comme le fait « split » en perl ou « explode » en php).

Par exemple pour découper les lignes de « /etc/passwd » nous pourrons utiliser le séparateur « : » :

fhh@mafalda ~/IFS $ IFS=: ; while read login mdp uid gid gecos home shell ; do
> echo "${gecos:=undef} > login $login (home : $home, shell : $shell)" ;
> done < /etc/passwd
root > login root (home : /root, shell : /bin/bash)
bin > login bin (home : /bin, shell : /bin/false)
undef > login mysql (home : /var/lib/mysql, shell : /bin/false)
...
FHH > login fhh (home : /users/fhh, shell : /bin/bash)
...

Note I : Dans cet exemple, si le « gecos » (nom complet) de l’utilisateur n’est pas défini, il est initialisé à undef.
Note II : « while read login reste ; do echo $login ; done < /etc/passwd" n'affichera que les logins (premier champ)

Impacte sur les arguments de scripts

Deux variables permettent de retourner la liste des arguments passés à un script shell : $@ et $* .

De prime abord, ces variables ne présentent pas de différences mais elles sont interprétées différemment si elles sont placées entre double quotes :

fhh@mafalda ~/IFS $ cat myifs.sh 
#!/bin/bash
IFS=:
echo "Liste des arguments :"
echo "\$@ sans double quotes > "$@ ;
echo "\$@ avec double quotes > $@" ;
echo "\$* sans double quotes > "$* ;
echo "\$* avec double quotes > $*" ;
fhh@mafalda ~/IFS $ ./myifs.sh a b cd efg
Liste des arguments :
$@ sans double quotes > a b cd efg
$@ avec double quotes > a b cd efg
$* sans double quotes > a b cd efg
$* avec double quotes > a:b:cd:efg

Placé entre double quotes $* utilise le séparateur standard pour retourner la liste des arguments passés au script.

Commande join/implode

En utilisant le comportement de « $* », nous pouvons coder une fonction destinée à joindre différents éléments en utilisant un séparateur choisi (comme le fait la fonction « join » en perl ou « implode » en php).

implode () {
	local IFS=$1 && shift ;
	echo "$*";
}

qui donne dans le shell

fhh@mafalda ~/IFS $ implode () {
>	local IFS=$1 && shift ;
>	echo "$*"
> }
fhh@mafalda ~/IFS $ implode : a b cd efg
a:b:cd:efg
fhh@mafalda ~/IFS $ implode "" a b cd efg
abcdefg

Cette fonction offre un comportement cohérent pour le traitement de chaînes de caractères avec espaces :

fhh@mafalda ~/IFS $ implode , $(ls)
fichier,1,fichier,2,myifs.sh,repertoire,avec,espace,1,repertoire,avec,espace,2
fhh@mafalda ~/IFS $ IFS=$'\n' ; implode , $(ls)
fichier 1,fichier 2,myifs.sh,repertoire avec espace 1,repertoire avec espace 2

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *