В чем разница в echo между zsh и bash?

#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]
  

Это должно устранить несоответствие, которое вы видите между интерпретаторами оболочки.