Si l'exemple suivant, qui définit la variable d'environnement IFS
sur un caractère de saut de ligne ...
IFS=$'\n'
Je sais ce qu'est la variable d'environnement IFS
et ce que la \n
caractère est (saut de ligne), mais pourquoi ne pas simplement utiliser la forme suivante: IFS="\n"
(qui ne fonctionne pas)?
Par exemple, si je souhaite parcourir toutes les lignes d'un fichier et utiliser une boucle for, je peux le faire:
for line in (< /path/to/file); do
echo "Line: $line"
done
Cependant, cela ne fonctionnera pas correctement à moins que IFS
soit défini sur un caractère de saut de ligne. Pour que cela fonctionne, je devrais faire ceci:
OLDIFS=$IFS
IFS=$'\n'
for line in (< /path/to/file); do
echo "Line: $line"
done
IFS=$OLDIFS
Note: Je n'ai pas besoin d'un autre moyen pour faire la même chose, j'en connais déjà beaucoup d'autres ... Je ne suis curieux que de cela $'\n'
et je me demandais si quelqu'un pourrait me donner une explication à ce sujet.
Normalement, bash
n'interprète pas les séquences d'échappement dans les littéraux de chaîne. Donc, si vous écrivez \n
ou "\n"
ou '\n'
, ce n'est pas un saut de ligne - c'est la lettre n
(dans le premier cas) ou une barre oblique inverse suivie de la lettre n
(dans les deux autres cas).
$'somestring'
est un syntaxe pour les littéraux de chaîne avec des séquences d'échappement. Donc, contrairement à '\n'
, $'\n'
est en fait un saut de ligne.
Juste pour donner à la construction son nom officiel : chaînes de la forme $'...'
sont appelés chaînes citées par ANSI C.
C’est-à-dire que, comme dans les chaînes C [ANSI], , les séquences d'échappement à jeu inversé sont reconnues et étendues à leur équivalent littéral (voir ci-dessous la liste complète des séquences d'échappement prises en charge).
Après cette extension, $'...'
Les chaînes se comportent de la même manière que '...'
chaînes - c’est-à-dire qu’elles sont traitées comme littéraux NON soumises à toute [autre] expansion du shell .
Par exemple, $'\n'
se développe en un caractère de nouvelle ligne littéral - qui est un littéral de chaîne bash classique (que '...'
ou "..."
) ne peut pas faire.[1]
Une autre caractéristique intéressante est que les chaînes citées par ANSI C peuvent échapper à '
(guillemets simples) comme \'
, qui, '...'
_ (chaînes simples, entre guillemets) ne peuvent pas:
echo $'Honey, I\'m home' # OK; this cannot be done with '...'
Liste des séquences d'échappement prises en charge :
Les séquences d'échappement de barre oblique inverse, le cas échéant, sont décodées comme suit:
\ une alerte (cloche)
\ b retour arrière
\ e\E un caractère d'échappement (pas ANSI C)
\ f form feed
\ n newline
\ r retour chariot
\ t onglet horizontal
\ v onglet vertical
\ backslash
\' simple citation
\" double citation
\ nnn le caractère de huit bits dont la valeur est la valeur octale nnn (un à trois chiffres)
\ xHH le caractère de huit bits dont la valeur est la valeur hexadécimale HH (un ou deux chiffres hexadécimaux)
\ uHHHH le caractère Unicode (ISO/IEC 10646) dont la valeur est la valeur hexadécimale HHHH (un à quatre chiffres hexadécimaux)
\ UHHHHHHHH le caractère Unicode (ISO/IEC 10646) dont la valeur est la valeur hexadécimale HHHHHHHH (un à huit chiffres hexadécimaux)
\ cx un caractère de contrôle-x
Le résultat étendu est indiqué entre guillemets simples, comme si le signe dollar n'avait pas été présent.
[1] Vous pouvez toutefois intégrer actuel newlines dans les chaînes '...' et "..."; c'est-à-dire que vous pouvez définir des chaînes qui s'étendent sur plusieurs lignes.
De http://www.linuxtopia.org/online_books/bash_guide_for_beginners/sect_03_03.html :
Les mots sous la forme "$ 'STRING'" sont traités de manière particulière. Word se développe en une chaîne, avec des caractères d'échappement avec une barre oblique inversée remplacés comme spécifié par la norme ANSI-C. Des séquences d'échappement avec une barre oblique inverse peuvent être trouvées dans la documentation Bash.
Je suppose que cela force le script à échapper le saut de ligne au standard ANSI-C approprié.
Re récupérer le IFS par défaut - this OLDIFS=$IFS
n'est pas nécessaire. Exécutez le nouvel IFS dans le sous-shell pour éviter de remplacer l'IFS par défaut:
ar=(123 321); ( IFS=$'\n'; echo ${ar[*]} )
En outre, je ne crois pas vraiment que vous récupériez complètement le vieil IFS. Vous devriez le citer deux fois pour éviter les sauts de ligne tels que OLDIFS="$IFS"
.
La chaîne ANSI C-cotée est un point clé. Merci à @ mklement0.
Vous pouvez tester les chaînes citées par ANSI C avec la commande od.
echo -n $'\n' | od -c
echo -n '\n' | od -c
echo -n $"\n" | od -c
echo -n "\n" | od -c
Les sorties:
0000000 \n
0000001
0000000 \ n
0000002
0000000 \ n
0000002
0000000 \ n
0000002
Vous pouvez connaître le sens clairement par les sorties.