J'ai vu quelques sujets similaires, mais ils se réfèrent à ne pas citer de variables, ce qui, je le sais, pourrait conduire à des résultats indésirables.
J'ai vu ce code et je me demandais s'il serait possible d'injecter quelque chose à exécuter lorsque cette ligne de code s'exécutera:
echo run after_bundle
Réponses:
Pour le cas spécifique
la citation n'est pas nécessaire. Aucune citation n'est nécessaire car l'argument to
echo
est des chaînes statiques qui ne contiennent aucune extension de variable ou substitution de commande, etc. Ce ne sont que "deux mots" (et comme le souligne Stéphane , elles sont en outre construites à partir du jeu de caractères portable ).Le "danger" survient lorsque vous traitez des données variables que le shell peut développer ou interpréter. Dans de tels cas, il faut veiller à ce que la coque fasse la bonne chose et que le résultat soit ce qui est prévu.
Les deux questions suivantes contiennent des informations pertinentes à ce sujet:
echo
est parfois utilisé pour "protéger" les commandes potentiellement nuisibles dans les réponses sur ce site. Par exemple, je peux montrer comment supprimer des fichiers ou déplacer des fichiers vers une nouvelle destination en utilisantou
Cela produirait des commandes sur le terminal au lieu de supprimer ou de renommer des fichiers. L'utilisateur pourrait alors inspecter les commandes, décider qu'elles semblent correctes, les supprimer
echo
et recommencer.Votre commande
echo run after_bundle
peut être une instruction pour l'utilisateur, ou peut être un morceau de code "mis en commentaire" qui est trop dangereux pour être exécuté sans en connaître les conséquences.En utilisant
echo
comme ça, il faut savoir ce que fait la commande modifiée et il faut garantir que la commande modifiée est réellement sûre (ce ne serait potentiellement pas le cas si elle contenait des redirections, et son utilisation sur un pipeline ne fonctionne pas, etc.)la source
echo rm "first file.txt" "second file.txt"
est en aucune façon différentecho rm "first" "file.txt" "second" "file.txt"
, la sortie des deux étant la même. Si vous souhaitez générer une commande shell en sortie, vous devez utiliserprintf '%q ' rm "first file.txt" "second file.txt"; echo
ou quelque chose d'équivalent qui régénère les guillemets syntaxiques qui évaluent leargv
passé.sh
n'est pas exactement un modèle inhabituel, et voir les gens se demander "pourquoi çafoo
marche quand je l'exécute sur une ligne de commande, mais ce script qui émet cette chaîne exacte avececho
devant la ligne ne fonctionne pas? " arrive tout le temps ici. Plus précisément, la sortie de débogage n'est pas utile si elle masque vos bogues - et si vos bogues sont liés à des citations,echo
ils ne les révéleront pas.Juste une note supplémentaire en plus de la bonne réponse de @ Kusalananda .
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 avececho
mais avec la façon dont le shell analyse son code.Par exemple dans un UTF-8:
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 lebash
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 pasvoilà
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: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înerareboot
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:(ce représentant cependant l'octet 0xd4 est rendu dans les paramètres régionaux). Exemple utilisant le moins nocif
uname
au lieu dereboot
:(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 commezsh
etbash
, 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:
Ou:
(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 pourecho
(ou au moins certainesecho
implémentations, au moins celles compatibles Unix):(notez que cela
\
est également spécial dans le premier argument deprintf
, 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:
(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 leargv[0]
etargc
est 3, bien que dans la plupart des shells de nos jours ilecho
soit intégré, de sorte queexec()
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]
toargv[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.la source
echo
...", je ne compte que 2 arguments passés à la commandeecho
, les arguments que je peux compter sontrun
etafter_bundle
, attention à expliquer comment vous compté et obtenu à 3 arguments?echo
). Voir(exec -a foo /bin/echo --help)
sur un système GNU et avec le shell GNU pour savoir comment passer un premier argument arbitraire de l'/bin/echo
utilité.$0
paramètres de position et dans les coquilles.iconv
dans lequelESC
est converti en'
. Essayez (à titre d'exemple):printf '\x1b'|iconv -f utf8 -t IBM-937|xxd
'
. Essayezprintf '\u2804' | iconv -f utf8 -t BRF | xxd
. Il y a des encodages dans lesquels il y a beaucoup de points de code qui deviennent'
. Environ 8695 codepoints dans UCS-4 deviennent'
. Essayezprintf '\U627' | iconv -cf utf-8 -t UCS-4
. Plusieurs (37) encodages convertissent le caractère 0x127 en a'
. Essayezprintf '\U127' | iconv -cf utf8 -t UCS2 |xxd