Просто дополнительная заметка поверх прекрасного ответа @ Kusalananda .
echo run after_bundle
это хорошо, потому что ни один из символов в этих трех аргументах не передается, чтобы echoсодержать символы, которые являются специальными для оболочки.
И (дополнительный момент, который я хотел бы здесь отметить), нет системного языкового стандарта, где эти байты могли бы преобразовываться в символы, которые являются специальными для оболочки.
Все эти символы находятся в том, что POSIX называет переносимым набором символов . Эти символы должны присутствовать и кодироваться одинаково во всех наборах символов в системе POSIX².
Так что командная строка будет интерпретироваться одинаково независимо от локали.
Теперь, если мы начнем использовать символы вне этого переносимого набора символов, будет хорошей идеей заключить их в кавычки, даже если они не являются специальными для оболочки, потому что в другой локали байты, которые их составляют, могут интерпретироваться как разные символы, которые могут стать специально для оболочки. Обратите внимание, что echoпроблема заключается в том, используете ли вы какую-либо другую команду или нет, а не в echoтом, как оболочка анализирует свой код.
Например, в UTF-8:
echo voilà | iconv -f UTF-8 -t //TRANSLIT
Это àкодируется как 0xc3 0xa0. Теперь, если у вас есть эта строка кода в сценарии оболочки, и сценарий оболочки вызывается пользователем, который использует локаль, чья кодировка не UTF-8, эти два байта могут составлять совершенно разные символы.
Например, в fr_FR.ISO8859-15локали, типичной французской локали, использующей стандартную однобайтовую кодировку, которая охватывает французский язык (то же самое, что используется для большинства западноевропейских языков, включая английский), этот байт 0xc3 интерпретируется как Ãсимвол, а 0xa0 как не символ пробела.
И в некоторых системах, таких как NetBSD³, этот неразрывный пробел считается пустым символом ( isblank()в нем он возвращает true, ему соответствует [[:blank:]]), и оболочки вроде бы bashпоэтому рассматривают его как разделитель токенов в своем синтаксисе.
Это означает, что вместо запуска echoс $'voil\xc3\xa0'аргументом as они запускают его с $'voil\xc3'аргументом as, что означает, что он не будет печататься voilàправильно.
Это становится намного хуже китайскими наборами символов , такими как BIG5, BIG5-HKSCS, GB18030, ГКИ , которые имеют много символов , чьих кодирования содержит ту же кодировку, что |, `, \(назвать наихудшее) (также , что нелепое SJIS, иначе Microsoft кандзи, за исключением что это ¥вместо \, но все еще рассматривается как \большинство инструментов, поскольку это закодировано как 0x5c).
Например, если в zh_CN.gb18030китайском языковом стандарте вы пишете скрипт:
echo 詜 reboot
Этот сценарий будет выводиться 詜 rebootв локали, использующей GB18030 или GBK, 唰 rebootв локали, использующей BIG5 или BIG5-HKSCS, но в локали C, использующей ASCII, или локали, использующей ISO8859-15 или UTF-8, будет rebootвыполняться из-за кодировки GB18030 из 詜0xd4 0x7c и 0x7c является кодировкой |в ASCII, поэтому мы в конечном итоге запустим:
echo �| reboot
(что, однако, представляет байт 0xd4, отображается в локали). Пример использования менее вредных unameвместо 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$
( unameбыл запущен).
Поэтому я бы посоветовал заключить в кавычки все строки, которые содержат символы вне переносимого набора символов.
Однако обратите внимание, что поскольку кодировка \и `встречается в кодировке некоторых из этих символов, лучше не использовать \или "..."или $'...'(внутри которых `и / или \все еще являются специальными), а '...'вместо этого заключать символы в кавычки вне переносимого набора символов.
Я не знаю ни одной системы, в которой есть языковой стандарт, в котором кодировка содержит какой-либо символ (кроме 'самого себя), кодировка которого содержит кодировку ', так что она '...'определенно должна быть самой безопасной.
Обратите внимание, что несколько оболочек также поддерживают $'\uXXXX'нотацию для выражения символов на основе их кодовой точки Unicode. В таких оболочках, как zshи bash, символ вставляется закодированным в кодировку локали (хотя это может вызвать неожиданное поведение, если эта кодировка не содержит этот символ). Это позволяет вам избегать вставки не-ASCII символов в ваш код оболочки.
Итак, выше:
echo 'voilà' | iconv -f UTF-8 -t //TRANSLIT
echo '詜 reboot'
Или:
echo $'voil\u00e0'
echo $'\u8a5c reboot'
(с оговоркой, он может сломать скрипт при запуске в локалях, которые не имеют этих символов).
Или лучше, так как \это также специально для echo(или, по крайней мере, для некоторых echo реализаций, по крайней мере, для Unix-совместимых):
printf '%s\n' 'voilà' | iconv -f UTF-8 -t //TRANSLIT
printf '%s\n' '詜 reboot'
(обратите внимание, что \это также особенное в первом аргументе для printf, поэтому лучше не использовать символы, не входящие в ASCII, в случае, если они могут содержать кодировку \).
Обратите внимание, что вы также можете сделать:
'echo' 'voilà' | 'iconv' '-f' 'UTF-8' '-t' '//TRANSLIT'
(это было бы излишним, но могло бы дать вам некоторое спокойствие, если вы не уверены, какие символы входят в переносимый набор символов)
Также убедитесь, что никогда не используете древнюю `...`форму подстановки команд (которая вводит другой уровень обработки обратной косой черты), но используйте $(...)вместо этого.
¹ технически, echoтакже передаются в качестве аргумента в echoполезность (чтобы сказать ему , как он был запущен), это argv[0]и argcесть 3, хотя в большинстве оболочек в настоящее время echoявляется встроенным, так что exec()из /bin/echoфайла со списком 3 аргументов моделируются оболочка. Также принято считать, что список аргументов начинается со второго ( argv[1]to argv[argc - 1]), поскольку это те команды, на которые в основном воздействуют команды.
² заметное исключение из того, что это нелепая ja_JP.SJISлокаль систем FreeBSD, чья кодировка не имеет \ни ~символа!
³ обратите внимание, что хотя многие системы (FreeBSD, Solaris, но не GNU) рассматривают U + 00A0 как a [[:blank:]]в локалях UTF-8, немногие делают это в других локалях, таких как ISO8859-15, возможно, чтобы избежать такого рода проблем.