Почему есть / bin / echo и зачем мне его использовать?

52

Я заметил, что в /bin/echoмоей системе Ubuntu MATE 17.04 есть двоичный исполняемый файл .

Я думал, это странно, потому что

$ type echo
echo is a shell builtin

Беглое тестирование предполагает, что это /bin/echoделает то же самое, что и встроенная Bash echo:

$ /bin/echo foo
foo
$ /bin/echo $USER
zanna

Итак, почему есть другая версия, echoотдельная от программы Bash, и почему или когда я хочу ее использовать?

Занна
источник
10
Обсуждение - unix.stackexchange.com/questions/1355/…
Пантера
2
@ bodhi.zazen Это довольно полезно, хотя это не одно и то же, потому что оно затрагивает обратную сторону этого вопроса. Этот вопрос спрашивает, почему echoон предоставляется как встроенная оболочка, тогда как этот вопрос спрашивает, почему он предоставляется как внешняя команда.
Элия ​​Каган
3
Одна из причин в том, что не все используют bash. Я предполагаю, что / bin / echo предшествует bash, и разработчики сочли полезным / эффективным включить его в качестве встроенного вместо использования исполняемого файла.
jamesqf

Ответы:

87

Если вы откроете bashприглашение и введете echoкоманду, она использует встроенную оболочку, а не работает /bin/echo. Причины, по которым все еще важно /bin/echoсуществовать:

  1. Вы не всегда используете оболочку. При различных обстоятельствах вы запускаете исполняемый файл напрямую, а не через оболочку.
  2. По крайней мере, в теории, некоторые оболочки не имеют echoвстроенных. Это на самом деле не требуется.

Для того, чтобы расширить свое присутствие на # 1, предположу , что вы хотите , чтобы переместить все обычные файлы , чьи имена стали с abcлюбой точкой srcк dest. Есть несколько способов сделать это, но один из них:

find src -name 'abc*' -type f -exec mv -nv {} dest/ \;

Но предположим, что вместо того, чтобы просто выполнить это, вы хотите видеть каждую команду, которая будет выполняться первой. Что ж, тогда вы можете echoвыполнить команду, как в других контекстах:

find src -name 'abc*' -type f -exec echo mv -nv {} dest/ \;

Но findне использует оболочку. Это работает /bin/echo.

Кроме того , findс -execили-execdir , то /bin/echoисполняемый файл будет называться другими программами , которые сами управляют программы , но не через оболочку. Это происходит с xargsкомандой (которая связана с find), а также в ряде других контекстах, например, в Exec=строке в виде .desktopфайла . Другой пример - когда вы запускаете sudo echo, что может пригодиться для тестирования, если sudoработает.

Аналогично, некоторые оболочки имеют printfвстроенные функции, но /usr/bin/printfтакже существуют.

Менее распространенная возможная причина, которую вы могли бы сознательно использовать, /bin/echoзаключается в том, что вы полагались на различия между ним и echoкомандой, предоставляемой вашей оболочкой. man echoдокументы /bin/echo; help echoв bash документах bashвстроенный. echoне очень переносим, ​​потому что разные реализации - как в операционных системах, так и в оболочках в одной и той же операционной системе - поддерживают разные варианты (например, -e) и различаются в обработке обратной косой черты . Конечно, лучше избегать полагаться на такие детали и использовать printfвместо этого, что гораздо более переносимо .

В bash, вы можете также сделать typeвстроенное шоу /bin/echo- при условии, что /binоно у вас, $PATHкак всегда должно быть - передав ему -aфлаг :

$ type -a echo
echo is a shell builtin
echo is /bin/echo
Элия ​​Каган
источник
21
А также потому, что в спецификации POSIX сказано, что она должна быть.
Гленн Джекман
4
@glennjackman Я надеялся, что кто-то опубликует ответ об этом, и я надеюсь, что вы решите это сделать! Однако здесь есть некоторая тонкость, поскольку ни Debian, ни Ubuntu, ни GNU Coreutils (ни проект GNU в целом) не пытаются соответствовать POSIX во всем . Например, POSIX настаивает на том, что cdисполняемый файл существует (который при запуске изменяет каталог и завершает работу, оставляя вызывающую программу там, где они были раньше), и некоторые ОС имеют ее. Может быть полезно сослаться на 4.1 в стандартах GNU .
Элия ​​Каган
@EliahKagan: Incidentaly / usr / bin / cd использует: команда каталога / usr / bin / cd запускает эту команду в этом каталоге. Если смена каталога не удалась, команда не запускается.
Джошуа
4
@ Joshua лучше использовать cdпросто как тест на возможность доступа к данному каталогу: в случае /usr/bin/cd some/dirуспеха за один раз вы проверили: а) который some/dirсуществует, б) что это каталог или ссылка на него, и в) необходимые разрешения для доступа к этому каталогу существуют; все без изменения собственного состояния.
Муру
1
@ CarlWitthoft, см. Почему printf лучше, чем echo? Кроме того /bin/echo, нет \bin\echo, если вы не используете Windows. ;)
Wildcard
31

Элия ​​отлично поработал, ответив на это, но я хочу прокомментировать часть «почему существует другая версия, echoотдельная от программы Bash». Это неправильный вопрос.

Правильный вопрос: почему это встроенное в первую очередь , когда оно могло быть (и является) совершенно хорошей внешней командой?

Для простоты взгляните на встроенные в dash, жалкие 38 (bash имеет 61, для сравнения, исходя из вывода compgen -b):

.               continue        getopts         readonly        type
:               echo            hash            return          ulimit
[               eval            jobs            set             umask
alias           exec            kill            shift           unalias
bg              exit            local           test            unset
break           export          printf          times           wait
cd              false           pwd             trap
command         fg              read            true

Сколько из них должно быть встроено? [, echo, false, printf, pwd, test, И trueне нужно быть встроенными функциями : Они все , что только может сделать встроенный (аффект или получить оболочки состояния, не доступна для внешних команд) не делать. Bash printfпо крайней мере использует преимущества встроенности: printf -v varсохраняет выходные данные в переменную var. timeв bash также особенное: будучи ключевым словом, вы можете синхронизировать произвольные списки команд в bash (у dash нет timeэквивалента). pwdНе обязательно быть встроенным - любая внешняя команда наследует текущий рабочий каталог (и это тоже внешняя команда ).:это исключение - вам нужен NOP, и :это так. Остальные выполняют действия, которые легко может выполнить внешняя команда.

Таким образом, пятая часть этих встроенных функций не должна быть встроенной. Тогда почему? Страница dashman * на самом деле объясняет, почему это встроенные (выделено мое):

Встроенные команды
 В этом разделе перечислены встроенные команды, которые встроены, потому что они
 необходимо выполнить некоторые операции, которые не могут быть выполнены отдельным
 процесс. В дополнение к этому есть несколько других команд, которые могут
 быть встроенным для эффективности (например, printf (1), echo (1), test (1) и т. д.).

Вот и все: эти встроенные функции существуют потому, что они используются так часто, в интерактивном режиме и в сценариях, а их функциональные возможности достаточно просты, чтобы оболочка могла выполнять свою работу. И так бывает: некоторые (?) Большинство снарядов взяли на работу ** Вернуться к. Из 2.9 BSD , и вы не найдете встроенную команду.shecho

Таким образом, вполне возможно, что минимальная оболочка может пропустить реализацию таких команд, как встроенные (хотя я не думаю, что какая-либо текущая оболочка это делает). Проект GNU coreutils не предполагает, что вы собираетесь запускать их в определенной оболочке, а POSIX требует этих команд. Итак, coreutils предоставляет их в любом случае и пропускает те, которые не имеют никакого значения вне оболочки.


* Это почти идентично соответствующему тексту man-страницы для оболочки Almquist , на которой основана черта, оболочка Debian Almquist.

** zshдоводит эту идею до крайности: команды, которые вы получаете, загружая различные модули, например zmv, являются вещами , в которые вы даже не думаете, что оболочка даже не нуждается . В этот момент реальный вопрос: зачем вам использовать bash вместо zsh, в котором есть все эти встроенные функции?

Мур
источник
1
Получается, что: тоже не нужно быть встроенным. Просто глупо не быть встроенным. Если только вы не сталкиваетесь с ранними проблемами уровня init rescue-floppy-disk (в этом случае я обнаружил, что pwd тоже не работает надежно), единственное наказание за отсутствие встроенной функции - ужасная производительность.
Джошуа
5
@ Джошуа: нет, :поскольку внешний не был бы действительно NOP, у вас все еще был бы PATHпоиск, попытка выполнить команду и т. Д., Когда все, что вам действительно нужно, это явно ничего не делать. :как встроенный делает это.
Муру
2
Bash действительно должен pwdбыть встроенным, чтобы он работал так, как он работает, с поведением по умолчанию, показывающим «логический» путь ( pwd -L). /bin/pwdможет реализовывать только pwd -Pповедение, показывающее вам фактические родительские каталоги, а не символическую ссылку, которую вы cdпросматривали.
Питер Кордес
2
Статус @PeterCordes pwdнемного скомпрометирован присутствием PWD, но да, это также случай bash, использующего встроенный статус для улучшения функциональности
muru