Я слышал, что printf
это лучше, чем echo
. Из своего опыта я могу вспомнить только один случай, когда мне приходилось использовать, printf
потому что echo
он не работал для подачи текста в какую-то программу на RHEL 5.8, но printf
работал. Но, видимо, есть и другие различия, и я хотел бы узнать, что это такое, а также есть ли конкретные случаи, когда использовать один против другого.
text-processing
echo
printf
amphibient
источник
источник
echo -e
?echo -e
не работаетsh
, толькоbash
(по какой-то причине), и, например, docker используетsh
по умолчанию для своихRUN
командecho -e
для меня работает в терминале Android, что по сутиsh
.Ответы:
По сути, это проблема переносимости (и надежности).
Первоначально
echo
не принимал никакой опции и ничего не расширял. Все, что он делал, это выводил свои аргументы, разделенные пробелом и заканчивающиеся символом новой строки.Теперь кто-то подумал, что было бы хорошо, если бы мы могли делать такие вещи, как
echo "\n\t"
вывод символов новой строки или табуляции, или иметь возможность не выводить завершающий символ новой строки.Затем они думали сложнее, но вместо того, чтобы добавить эту функциональность в оболочку (например,
perl
когда внутри двойных кавычек\t
фактически означает символ табуляции), они добавили ееecho
.Дэвид Корн понял ошибку и ввел новую форму кавычки оболочки:
$'...'
которая позже была скопированаbash
и ,zsh
но это было уже слишком поздно к тому времени.Теперь, когда стандартная UNIX
echo
получает аргумент, который содержит два символа,\
иt
вместо их вывода он выводит символ табуляции. И как только он видит\c
в аргументе, он прекращает выводить (поэтому завершающий символ новой строки тоже не выводится).Другие оболочки / производители / версии Unix решили сделать это по-другому: они добавили
-e
опцию расширения escape-последовательностей и-n
опцию не выводить завершающий перевод строки. У некоторых есть-E
возможность отключить escape-последовательности, у некоторых есть,-n
но нет-e
, список escape-последовательностей, поддерживаемых однойecho
реализацией, не обязательно совпадает с поддерживаемым другой.У Sven Mascheck есть хорошая страница, которая показывает масштаб проблемы .
В тех
echo
реализациях, которые поддерживают опции, обычно нет поддержки--
для обозначения конца опций (echo
встроенные в некоторые не-подобные Борну оболочки делают, и zsh поддерживает-
это), поэтому, например, трудно вывести"-n"
с помощьюecho
in много снарядов.На некоторых оболочках , как
bash
¹ илиksh93
² илиyash
($ECHO_STYLE
переменная), поведение даже зависит от того, как оболочка была собрана или среда (ГНУecho
«поведение s также изменится , если$POSIXLY_CORRECT
в окружающей среде и с версией 4 ,zsh
» s сbsd_echo
опцией, некоторые на основе pdksh с ихposix
опцией, или они называются как,sh
или нет). Таким образом, двеbash
echo
пары, даже из одной и той же версииbash
, не могут вести себя одинаково.POSIX говорит: если первый аргумент
-n
или любой аргумент содержит обратную косую черту, то поведение не определено .bash
echo в этом отношении не является POSIX, напримерecho -e
, не выводится,-e<newline>
как того требует POSIX. Спецификация UNIX более строгая, она запрещает-n
и требует расширения некоторых escape-последовательностей, в том числе и\c
той, которая прекращает вывод.Эти спецификации на самом деле не приходят на помощь, поскольку многие реализации не соответствуют друг другу. Даже некоторые сертифицированные системы, такие как macOS 5 , не совместимы.
Чтобы действительно представить текущую реальность, POSIX должен фактически сказать : если первый аргумент соответствует
^-([eEn]*|-help|-version)$
расширенному регулярному выражению или какой-либо аргумент содержит обратную косую черту (или символы, кодировка которых содержит кодировку символа обратной косой черты, какα
в локалях, использующих кодировку BIG5), то поведение неопределенные.В общем, вы не знаете, что
echo "$var"
будет выводиться, пока не убедитесь, что$var
он не содержит символов обратной косой черты и не начинается с-
. Спецификация POSIX на самом деле говорит нам использоватьprintf
вместо этого в этом случае.Так что это означает, что вы не можете использовать
echo
для отображения неконтролируемых данных. Другими словами, если вы пишете сценарий, и он принимает внешние данные (от пользователя в качестве аргументов или имена файлов из файловой системы ...), вы не можете использовать егоecho
для отображения.Хорошо:
Это не:
(Хотя он будет работать нормально с некоторыми (не совместимыми с UNIX)
echo
реализациями, такими как, напримерbash
, когдаxpg_echo
опция не была включена тем или иным образом, например, во время компиляции или через среду).file=$(echo "$var" | tr ' ' _)
не в порядке в большинстве реализаций (исключение составляютyash
сECHO_STYLE=raw
(с той оговоркой , чтоyash
«ы переменные не могут занимать произвольные последовательности байтов , так не произвольные имена файлов) иzsh
» Secho -E - "$var"
6 ).printf
, с другой стороны, является более надежным, по крайней мере, когда оно ограничено основным использованиемecho
.Выводит содержимое, за
$var
которым следует символ новой строки, независимо от того, какой символ он может содержать.Выводит его без завершающего символа новой строки.
Теперь также есть различия между
printf
реализациями. В POSIX есть ядро функций, но есть множество расширений. Например, некоторые поддерживают%q
кавычки аргументов, но как это делается, зависит от оболочки к оболочке, некоторые поддерживают\uxxxx
символы Юникода. Поведение варьируется дляprintf '%10s\n' "$var"
многобайтовых локалей, есть как минимум три разных результата дляprintf %b '\123'
Но, в конце концов, если вы придерживаетесь набора функций POSIX
printf
и не пытаетесь делать с ним что-то слишком сложное, у вас нет проблем.Но помните, что первый аргумент - это формат, поэтому он не должен содержать переменные / неконтролируемые данные.
Более надежный
echo
может быть реализован с помощьюprintf
, например:Подобную оболочку (которая подразумевает создание дополнительного процесса в большинстве реализаций оболочки) можно избежать, используя
local IFS
множество оболочек или написав его следующим образом:Примечания
1. как
bash
«secho
поведение может быть изменено.Во
bash
время выполнения есть две вещи, которые управляют поведениемecho
(помимоenable -n echo
или переопределениемecho
как функции или псевдонима):xpg_echo
bash
опция иbash
находится ли она в режиме posix.posix
Режим можно включить, если онbash
вызывается какsh
или если онPOSIXLY_CORRECT
находится в среде или сposix
параметром:Поведение по умолчанию в большинстве систем:
xpg_echo
расширяет последовательности, поскольку UNIX требует:Это все еще отличием
-n
и-e
(и-E
):С
xpg_echo
и режим POSIX:На этот раз
bash
POSIX и UNIX совместимы. Обратите внимание, что в режиме POSIXbash
он по-прежнему не соответствует POSIX, поскольку не выводит-e
в:Значения по умолчанию для xpg_echo и POSIX могут быть определены во время компиляции с
--enable-xpg-echo-default
и--enable-strict-posix-default
опции кconfigure
сценарию. Это обычно то, что последние версии OS / X делают, чтобы построить их/bin/sh
.Никакая реализация / распространение Unix / Linux в их здравом уме, как правило, не делает этого,. На самом деле, это не так,/bin/bash
хотя/bin/bash
кажется , что Oracle поставляется с Solaris 11 (в дополнительном пакете), похоже, скомпилирован--enable-xpg-echo-default
(это было не так в Solaris 10).2. Как
ksh93
«secho
поведение может быть изменено.В
ksh93
, будь тоecho
расширяется экранирующие последовательности или нет , и распознает варианты зависит от содержания$PATH
и / или$_AST_FEATURES
переменных окружения.Если
$PATH
содержит компонент, который содержит/5bin
или/xpg
перед компонентом/bin
или,/usr/bin
то он ведет себя как SysV / UNIX (расширяет последовательности, не принимает параметры). Если он находит/ucb
или/bsd
сначала, или если$_AST_FEATURES
7 содержитUNIVERSE = ucb
, то он ведет себя как BSD 3 (-e
чтобы разрешить расширение, распознает-n
).По умолчанию это системно-зависимый BSD на Debian (см. Вывод
builtin getconf; getconf UNIVERSE
последних версий ksh93):3. BSD для эха -е?
Ссылка на BSD для обработки этой
-e
опции немного вводит в заблуждение. Большинство из этих различных и несовместимыхecho
поведений были все представлены в AT & T:\n
,\0ooo
,\c
В верстаке программиста UNIX (на базе Unix V6), а остальное (\b
,\r
...) в Unix System III Ref .-n
в Unix V7 (Деннис Ричи Реф )-e
в Unix V8 (Деннис Ричи Реф )-E
сам по себе, возможно, изначально произошелbash
(CWRU / CWRU.chlog в версии 1.13.5 упоминает, что Брайан Фокс добавил его в 1992-10-18 гг., GNUecho
скопировал его вскоре после выхода в sh-utils-1.8, выпущенном 10 дней спустя)Хотя
echo
встроенные функцииsh
BSD или BSD поддерживали-e
со дня, когда они начали использовать для этого оболочку Almquist в начале 90-х, автономнаяecho
утилита по сей день не поддерживает их там ( FreeBSD по-echo
прежнему не поддерживает-e
, хотя и поддерживает-n
как Unix V7 (а также,\c
но только в конце последнего аргумента)).Обработка
-e
была добавлена кksh93
«с ,echo
когда в BSD вселенной в версии ksh93r выпущен в 2006 году и могут быть отключены во время компиляции.4. GNU echo изменение поведения в 8.31
Поскольку Coreutils 8,31 (и это совершает ), GNU
echo
Теперь расширяет управляющие последовательности по умолчанию , когда POSIXLY_CORRECT находится в окружающей среде, в соответствии с поведениемbash -o posix -O xpg_echo
«ыecho
встроенной команды (см сообщения об ошибке ).5. macOS
echo
Большинство версий macOS получили сертификацию UNIX от OpenGroup .
Их
sh
встроенная программаecho
совместима, так как онаbash
(очень старая версия) построена сxpg_echo
включенной по умолчанию, но их автономнаяecho
утилита - нет.env echo -n
ничего не выводит вместо-n<newline>
,env echo '\n'
выводит\n<newline>
вместо<newline><newline>
.Это
/bin/echo
тот из FreeBSD, который подавляет вывод новой строки, если первый аргумент равен-n
или (с 1995 года), если последний аргумент заканчивается\c
, но не поддерживает никакие другие последовательности обратной косой черты, требуемые UNIX, даже\\
.6.
echo
реализации, которые могут вывести произвольные данные дословноСтрого говоря, вы также можете сосчитать, что FreeBSD / macOS
/bin/echo
выше (неecho
встроенная в их оболочку ), где можно записатьzsh
secho -E - "$var"
илиyash
sECHO_STYLE=raw echo "$var"
(printf '%s\n' "$var"
):Реализации, которые поддерживают
-E
и-n
(или могут быть настроены) также могут делать:И
zsh
Secho -nE - "$var"
(printf %s "$var"
) может быть написано7.
_AST_FEATURES
и АСТUNIVERSE
Он
_AST_FEATURES
не предназначен для прямой манипуляции, он используется для распространения параметров конфигурации AST во время выполнения команды. Конфигурация предназначена для выполнения через (недокументированный)astgetconf()
API. Внутриksh93
, тоgetconf
встроенный (включеноbuiltin getconf
или вызоваcommand /opt/ast/bin/getconf
) является интерфейсомastgetconf()
Например, вам нужно
builtin getconf; getconf UNIVERSE = att
изменитьUNIVERSE
настройку наatt
(вызываяecho
поведение SysV среди прочего). После этого вы увидите, что$_AST_FEATURES
переменная окружения содержитUNIVERSE = att
.источник
echo
расширения\x
последовательностей в противоположность оболочке как части синтаксиса цитирования заключается в том, что вы можете затем вывести NUL-байт (еще один ошибочный дизайн Unix - это разделенный нулями разделитель). строк, где половина системных вызовов (например,execve()
не может принимать произвольные последовательности байтов)printf
кажется, что это проблема, так как большинство реализаций делают это неправильно. Единственная правильная реализация, о которой я знаю, находится в,bosh
и на странице от Свена Мащека не перечисляются проблемы с нулевыми байтами через\0
.Возможно, вы захотите использовать
printf
для его параметров форматирования.echo
полезно, когда дело доходит до печати значения переменной или (простой) строки, но это все, что нужно сделать.printf
может в основном делать то, что может делать C-версия.Пример использования и возможности:
Echo
:printf
:Источники:
источник
echo
для печати переменной может завершиться ошибкой, если значение переменной содержит метасимволы.Одним из «преимуществ», если вы хотите так его назвать, будет то, что вам не нужно говорить, что он
echo
интерпретирует определенные escape-последовательности, такие как\n
. Он знает, как их интерпретировать, и для этого не требуется-e
.(NB: последнее
\n
необходимо,echo
подразумевается, если вы не предоставите-n
опцию)против
Обратите внимание на последний
\n
вprintf
. В конце концов, это вопрос вкуса и требований, что вы используете:echo
илиprintf
.источник
/usr/bin/echo
иbash
встроенный.dash
,ksh
Иzsh
встроенныйecho
не нужно-e
переключиться на расширение обратной косой чертой символов.printf '%s\n' 'foo\bar
.Одним из недостатков
printf
является производительность, потому что встроенная оболочкаecho
намного быстрее. Это особенно заметно в Cygwin, где каждый экземпляр новой команды вызывает большие накладные расходы Windows. Когда я изменил свою эхо-программу с использования/bin/echo
на эхо оболочки, производительность почти удвоилась. Это компромисс между мобильностью и производительностью. Это не хлам, чтобы всегда использоватьprintf
.источник
printf
в настоящее время встроен в большинство оболочек (bash, dash, ksh, zsh, yash, некоторые производные pdksh ... включает в себя оболочки, обычно встречающиеся и в cygwin). Единственными заметными исключениями являются некоторыеpdksh
производные.printf
для вывода нулевых байтов, но некоторые реализации интерпретируют `\ c 'в строке формата, даже если они не должны.printf
POSIX не определяет поведение POSIX, если вы используете\c
в строке формата, поэтомуprintf
реализации могут делать все, что захотят в этом отношении. Например, некоторые обрабатывают его так же, как в PWBecho
(приводит к выходу printf), ksh использует его для\cA
управляющих символов (для аргумента формата printf и для,$'...'
но не дляecho
norprint
!). Не уверен, что это связано с печатью байтов NUL, или, может быть, вы ссылаетесь наksh
sprintf '\c@'
?