#bash #escaping #echo #newline #zsh
#bash #экранирование #echo #перевод строки #zsh
Вопрос:
В bash в данном конкретном случае echo ведет себя следующим образом:
$ bash -c 'echo "anb"'
anb
но в zsh то же самое получается совсем по-другому…:
$ zsh -c 'echo "anb"'
a
b
и fwiw в fish, потому что мне было любопытно:
$ fish -c 'echo "anb"'
anb
Я понял, что могу запустить:
$ zsh -c 'echo -E "anb"'
anb
Но теперь я беспокоюсь, что могу наткнуться на еще больше ошибок в такой базовой операции. (Таким образом, мое исследование fish: если мне придется вносить изменения на таком низком уровне для zsh, почему бы не пройти весь путь и не переключиться на что-то, что явно отличается от того, что так отличается?)
Я сам не нашел никакой документации, которая помогла бы прояснить эту разницу в echo в bash против zsh или на страницах, непосредственно перечисляющих различия, так что может кто-нибудь здесь перечислить их? И, может быть, укажите мне на какой-либо более широкий набор потенциально важных ошибок при переключении, которые бы охватывали этот случай?
Комментарии:
1. Вот почему вы не используете
echo
для печати данных, если это не имеет никаких последствий.printf %s\n "anb"
будет вести себя одинаково независимо от оболочки.
Ответ №1:
Обычно предпочитают printf
для получения согласованных результатов.
Если вам нужна предсказуемая последовательная echo
реализация, вы можете переопределить ее своей собственной функцией.
Это будет вести себя одинаково, независимо от оболочки.
echo(){ printf %s\n "$*";}
echo "anb"
Ответ №2:
echo
хорош и переносим только для печати литеральных строк, которые заканчиваются новой строкой, но он не подходит для чего-то более сложного, вы можете подробнее прочитать об этом в этом ответе и в документации Shellcheck здесь .
Несмотря на то, что в соответствии с POSIX каждая реализация должна понимать последовательности символов без каких-либо дополнительных опций, вы не можете полагаться на это. Как вы уже заметили, в Bash, например echo 'anb'
, выдает anb
, но его можно изменить с xpg_echo
помощью опции оболочки:
$ echo 'anb'
anb
$ shopt -s xpg_echo
$ echo 'anb'
a
b
И, может быть, укажите мне какой-либо более широкий набор потенциально
важных ошибок при переключении, которые бы охватывали этот случай?
Обратите внимание, что несоответствие между различными echo
реализациями может проявляться не только в shell, но и в других местах, где shell используется косвенно, например, в Makefile. Однажды я наткнулся на Makefile, который выглядел так:
all:
@echo "targettdoes this"
@echo "another-targettdoes this"
make
использует /bin/sh для выполнения этих команд, поэтому, если /bin/sh является символической
ссылкой на bash в вашей системе, вы получаете:
$ make
targettdoes this
another-targettdoes this
Если вы хотите использовать переносимость в оболочке printf
. Это:
printf 'anbn'
должен выдавать одинаковый результат в большинстве оболочек.
Ответ №3:
echo предоставляет один и тот же вывод, независимо от интерпретатора оболочки, из которого он вызывается.
Разница заключается в том, что каждая оболочка будет выводить стандартный выходной буфер на экран. zsh автоматически интерпретирует escape-символы / последовательности (например, » n t v r …» или escape-последовательности ANSI) там, где bash этого не делает.
Используя bash, вам нужно будет указать флаг -e для печати новых строк:
#Input:
echo "[text-to-print]n[text-to-print-on-newline]"
#Output:
[text-to-print]n[text-to-print-on-newline]
#Input:
echo -e "[text-to-print]n[text-to-print-on-newline]"
#Output:
[text-to-print]
[text-to-print-on-newline]
Используя zsh, интерпретатор выполняет интерпретацию escape-последовательности самостоятельно, и результат остается одинаковым независимо от флага -e:
#Input:
echo "[text-to-print]n[text-to-print-on-newline]"
#Output:
[text-to-print]
[text-to-print-on-newline]
#Input:
echo -e "[text-to-print]n[text-to-print-on-newline]"
#Output:
[text-to-print]
[text-to-print-on-newline]
Это должно устранить несоответствие, которое вы видите между интерпретаторами оболочки.