Juste une note supplémentaire en plus de la bonne réponse de @ Kusalananda .
echo run after_bundle
est correct car aucun des caractères de ces 3 arguments¹ n'est passé pour echo
contenir des caractères spéciaux pour le shell.
Et (le point supplémentaire que je veux faire ici), il n'y a pas de paramètres régionaux du système où ces octets pourraient se traduire par des caractères spéciaux pour le shell.
Tous ces caractères se trouvent dans ce que POSIX appelle le jeu de caractères portable . Ces caractères doivent être présents et codés de la même manière dans tous les jeux de caractères d'un système POSIX².
Ainsi, cette ligne de commande sera interprétée de la même manière, indépendamment des paramètres régionaux.
Maintenant, si nous commençons à utiliser des caractères en dehors de ce jeu de caractères portable, c'est une bonne idée de les citer même s'ils ne sont pas spéciaux pour le shell, car dans un autre endroit, les octets qui les constituent peuvent être interprétés comme des caractères différents qui pourraient devenir spécial à la coquille. Notez que c'est que vous utilisiez echo
ou toute autre commande, le problème n'est pas avec echo
mais avec la façon dont le shell analyse son code.
Par exemple dans un UTF-8:
echo voilà | iconv -f UTF-8 -t //TRANSLIT
Cela à
est codé comme 0xc3 0xa0. Maintenant, si vous avez cette ligne de code dans un script shell et que le script shell est invoqué par un utilisateur qui utilise un paramètre régional dont le jeu de caractères n'est pas UTF-8, ces deux octets pourraient faire des caractères très différents.
Par exemple, dans un fr_FR.ISO8859-15
environnement local, un environnement local français typique utilisant le jeu de caractères standard à un octet qui couvre la langue française (le même que celui utilisé pour la plupart des langues d'Europe occidentale, y compris l'anglais), cet octet 0xc3 est interprété comme le Ã
caractère et 0xa0 comme le non briser le caractère de l'espace.
Et sur quelques systèmes comme NetBSD³, cet espace insécable est considéré comme un caractère vide ( isblank()
sur il retourne vrai, il est assorti de [[:blank:]]
) et les shells comme le bash
traitent donc comme un délimiteur de jeton dans leur syntaxe.
Cela signifie qu'au lieu de s'exécuter echo
avec $'voil\xc3\xa0'
comme argument, ils l'exécutent avec $'voil\xc3'
comme argument, ce qui signifie qu'il ne s'imprimera pas voilà
correctement.
Il obtient bien pire avec les jeux de caractères chinois comme BIG5, BIG5-HKSCS, GB18030, GBK qui ont beaucoup de caractères dont le codage contient le même encodage que le |
, `
, \
(pour nommer le pire) (que SJIS risible, alias Microsoft Kanji, à l' exception que c'est au ¥
lieu de \
, mais toujours traité comme \
par la plupart des outils car il est encodé en 0x5c).
Par exemple, si dans un zh_CN.gb18030
environnement chinois, vous écrivez un script comme:
echo 詜 reboot
Ce script sortira 詜 reboot
dans un environnement local utilisant GB18030 ou GBK, 唰 reboot
dans un environnement local utilisant BIG5 ou BIG5-HKSCS, mais dans un environnement local C utilisant ASCII ou un environnement local utilisant ISO8859-15 ou UTF-8, entraînera reboot
l'exécution parce que l'encodage GB18030 de 詜
est 0xd4 0x7c et 0x7c est l'encodage |
en ASCII nous finissons donc en cours d' exécution:
echo �| reboot
(ce représentant cependant l'octet 0xd4 est rendu dans les paramètres régionaux). Exemple utilisant le moins nocif uname
au lieu de reboot
:
$ echo $'echo \u8a5c uname' | iconv -t gb18030 > myscript
$ LC_ALL=zh_CN.gb18030 bash ./myscript | sed -n l
\324| uname$
$ LC_ALL=C bash ./myscript | sed -n l
Linux$
(a uname
été exécuté).
Donc, mon conseil serait de citer toutes les chaînes qui contiennent des caractères en dehors du jeu de caractères portable.
Cependant, notez que puisque l'encodage de \
et `
se trouve dans l'encodage de certains de ces caractères, il est préférable de ne pas utiliser \
ou "..."
ou $'...'
(à l'intérieur duquel `
et / ou \
sont toujours spéciaux), mais '...'
plutôt de citer des caractères en dehors du jeu de caractères portable.
Je ne connais aucun système qui a une locale où le jeu de caractères a un caractère (autre que '
lui bien sûr) dont l'encodage contient l'encodage de '
, donc ceux-ci '...'
devraient certainement être les plus sûrs.
Notez que plusieurs shells prennent également en charge une $'\uXXXX'
notation pour exprimer des caractères en fonction de leur point de code Unicode. Dans les shells comme zsh
et bash
, le caractère est inséré encodé dans le jeu de caractères de la locale (bien que cela puisse provoquer des comportements inattendus si ce jeu de caractères n'a pas ce caractère). Cela vous permet d'éviter d'insérer des caractères non ASCII dans votre code shell.
Donc ci-dessus:
echo 'voilà' | iconv -f UTF-8 -t //TRANSLIT
echo '詜 reboot'
Ou:
echo $'voil\u00e0'
echo $'\u8a5c reboot'
(avec la mise en garde, il pourrait casser le script lorsqu'il est exécuté dans des locales qui n'ont pas ces caractères).
Ou mieux, car \
est également spécial pour echo
(ou au moins certaines echo
implémentations, au moins celles compatibles Unix):
printf '%s\n' 'voilà' | iconv -f UTF-8 -t //TRANSLIT
printf '%s\n' '詜 reboot'
(notez que cela \
est également spécial dans le premier argument de printf
, il est donc préférable d'éviter les caractères non ASCII au cas où ils pourraient contenir le codage de \
).
Notez que vous pouvez également faire:
'echo' 'voilà' | 'iconv' '-f' 'UTF-8' '-t' '//TRANSLIT'
(ce serait exagéré mais pourrait vous donner une certaine tranquillité d'esprit si vous n'êtes pas sûr des caractères dans le jeu de caractères portable)
Assurez-vous également de ne jamais utiliser l'ancienne `...`
forme de substitution de commandes (qui introduit un autre niveau de traitement de barre oblique inverse), mais utilisez-la à la $(...)
place.
¹ techniquement, echo
est également passé comme argument à l' echo
utilitaire (pour lui dire comment il a été invoqué), c'est le argv[0]
et argc
est 3, bien que dans la plupart des shells de nos jours il echo
soit intégré, de sorte que exec()
d'un /bin/echo
fichier avec une liste de 3 arguments est simulé par le coquille. Il est également courant de considérer la liste d'arguments comme commençant par le second ( argv[1]
to argv[argc - 1]
) car ce sont ceux sur lesquels les commandes agissent principalement.
² une exception notable à cela étant le ja_JP.SJIS
lieu ridicule des systèmes FreeBSD dont le jeu de caractères n'a \
ni ~
caractère ni !
³ notez que bien que de nombreux systèmes (FreeBSD, Solaris, pas GNU cependant) considèrent U + 00A0 comme un [[:blank:]]
dans les paramètres régionaux UTF-8, peu le font dans d'autres paramètres régionaux comme ceux utilisant ISO8859-15, peut-être pour éviter ce genre de problème.