Dlaczego istnieje / bin / echo i dlaczego miałbym go używać?

52

Zauważyłem, że /bin/echow moim systemie Ubuntu MATE 17.04 istnieje plik binarny .

Myślałem, że to dziwne, ponieważ

$ type echo
echo is a shell builtin

Testy kursowe sugerują, że /bin/echorobi to samo, co wbudowane Bash echo:

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

Dlaczego więc istnieje inna wersja programu echoniezależnego od programu Bash i dlaczego lub kiedy miałbym z niego korzystać?

Zanna
źródło
2
@ bodhi.zazen Jest to całkiem przydatne, chociaż nie jest takie samo, ponieważ rozwiązuje odwrotność tego pytania. To pytanie pyta, dlaczego echojest dostarczane jako wbudowana powłoka, podczas gdy to pytanie pyta, dlaczego jest dostarczane jako polecenie zewnętrzne.
Eliah Kagan
3
Jednym z powodów jest to, że nie wszyscy używają bash. Domyślam się, że / bin / echo poprzedza bash, a programiści uznali za użyteczne / wydajne włączenie go jako wbudowanego zamiast korzystania z pliku wykonywalnego.
jamesqf

Odpowiedzi:

87

Jeśli otworzysz bashmonit i wpiszesz echopolecenie, które używa wbudowanej powłoki, a nie działa /bin/echo. Powody, dla których nadal jest ważne /bin/echo, to:

  1. Nie zawsze używasz powłoki. W różnych okolicznościach uruchamiasz plik wykonywalny bezpośrednio, a nie przez powłokę.
  2. Przynajmniej teoretycznie niektóre pociski nie mają echowbudowanego. To nie jest faktycznie wymagane.

Aby rozwinąć na # 1, załóżmy, że chciał, aby przenieść wszystkie pliki, których nazwy regularne rozpoczął się abcw dowolnym miejscu srcna dest. Można to zrobić na kilka sposobów, ale jednym z nich jest:

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

Załóżmy jednak, że zamiast uruchamiać to, chcesz zobaczyć każde polecenie, które zostanie uruchomione jako pierwsze. Cóż, możesz echoprzejść do polecenia, tak jak w innych kontekstach:

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

Ale findnie używa powłoki. To działa /bin/echo.

Poza tym findz -execlub-execdir , /bin/echoplik wykonywalny będzie wywoływany przez inne programy, które same uruchamiają programy, ale nie przez powłokę. To się dzieje z xargspoleceniem (która jest związana do find), a także w wielu innych sytuacjach, takich jak na Exec=linii z pomocą .desktoppliku . Innym przykładem jest uruchamianie sudo echo, które może być przydatne do testowania, czy sudodziała.

Podobnie niektóre powłoki mają printfwbudowane funkcje, ale /usr/bin/printfrównież istnieją.

Mniej powszechnym możliwym powodem, dla którego możesz celowo użyć, /bin/echojest poleganie na różnicach między nim a echopoleceniem dostarczonym przez twoją powłokę. man echodokumenty /bin/echo; help echow bash dokumentach bashwbudowanego. echonie jest bardzo przenośny, ponieważ różne implementacje - zarówno w systemach operacyjnych, jak i powłokach w tym samym systemie operacyjnym - obsługują różne opcje (np. -e) i różnią się traktowaniem ukośników odwrotnych . Oczywiście lepiej unikać polegania na takich szczegółach i używać printfzamiast tego, który jest o wiele bardziej przenośny .

W bash, możesz sprawić, by typewbudowany pokazał się /bin/echorównież - zakładając, że /binjest w twoim, $PATHjak zawsze powinien być - przekazując mu -aflagę :

$ type -a echo
echo is a shell builtin
echo is /bin/echo
Eliah Kagan
źródło
21
A także dlatego, że specyfikacja POSIX mówi, że musi być jeden.
glenn jackman
4
@glennjackman Miałem nadzieję, że ktoś opublikuje odpowiedź na ten temat, i mam nadzieję, że zdecydujesz się to zrobić! W grę wchodzi jednak subtelność, ponieważ ani Debian, Ubuntu, ani GNU Coreutils (ani ogólnie Projekt GNU) nie starają się przestrzegać POSIX we wszystkim . Na przykład POSIX nalega na cdistnienie pliku wykonywalnego (który po uruchomieniu zmienia katalog i kończy pracę, pozostawiając program wywołujący tam, gdzie był wcześniej), a niektóre systemy operacyjne go mają. Przydatne może być cytowanie 4.1 w standardach GNU .
Eliah Kagan
@EliahKagan: Incidentaly / usr / bin / cd ma komendę use: / usr / bin / cd, która uruchamia tę komendę w tym katalogu. Jeśli zmiana katalogu nie powiedzie się, polecenie się nie uruchamia.
Joshua
4
@Joshua lepszym zastosowaniem cdjest po prostu test możliwości dostępu do danego katalogu: jeśli się /usr/bin/cd some/dirpowiedzie, w jednym ujęciu przetestowałeś: a) który some/diristnieje, b) że jest to katalog lub link do jednego, oraz c) istnieją wymagane uprawnienia dostępu do tego katalogu; wszystko bez zmiany własnego stanu.
muru
1
@CarlWitthoft, zobacz Dlaczego printf jest lepszy niż echo? Również to /bin/echo, nie \bin\echo, chyba, że używasz systemu Windows. ;)
Wildcard,
31

Eliah wykonał świetną robotę, odpowiadając na to pytanie, ale chcę skomentować część „dlaczego istnieje inna wersja echooddzielna od programu Bash”. To złe pytanie.

Prawidłowe pytanie brzmi: dlaczego jest to wbudowane przede wszystkim , skoro mogło to być (i jest) doskonale zewnętrzne polecenie?

Dla uproszczenia spójrz na wbudowane funkcje w myślniku, marne 38 (bash ma 61, dla porównania, przechodząc przez wynik 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

Ile z nich wymaga wbudowania? [, echo, false, printf, pwd, test, I truenie trzeba być builtins: Nie wszystko, co tylko może rób wbudowane (wpływ lub uzyskanie stanu powłoki, która nie jest dostępna dla poleceń zewnętrznych). Bash korzysta printfprzynajmniej z wbudowanej funkcji: printf -v varzapisuje dane wyjściowe do zmiennej var. timew bash jest również wyjątkowy: będąc słowem kluczowym, możesz mierzyć dowolne listy poleceń w bash (myślnik nie ma timeodpowiednika). pwdnie musi też być wbudowany - każde polecenie zewnętrzne odziedziczy bieżący katalog roboczy (i to też polecenie zewnętrzne ).:jest wyjątkiem - potrzebujesz NOP i tak :jest. Reszta wykonuje czynności, które może łatwo wykonać polecenie zewnętrzne.

Tak więc jedna piąta wbudowanych nie musi być wbudowana. Dlaczego więc? Strona dashman * wyjaśnia, dlaczego są one wbudowane (moje podkreślenie):

Wbudowane
 W tej sekcji wymieniono wbudowane polecenia, które są wbudowane, ponieważ one
 trzeba wykonać operację, której nie można wykonać osobno
 proces. Oprócz nich istnieje kilka innych poleceń, które mogą
 być wbudowanym w celu zwiększenia wydajności (np. printf (1), echo (1), test (1) itp.).

To wszystko: te wbudowane funkcje są dostępne, ponieważ są używane tak często, interaktywnie i w skryptach, a ich funkcjonalność jest na tyle prosta, że ​​powłoka może wykonać zadanie. I tak to się dzieje: niektóre (większość?) Muszle wziął w pracy ** wracać. Od 2,9 BSD i nie znajdzie polecenie wbudowane.shecho

Jest więc całkiem możliwe, że minimalna powłoka może pominąć implementację takich poleceń jak wbudowane (nie sądzę jednak, że jakakolwiek obecna powłoka to robi). Projekt GNU coreutils nie zakłada, że ​​będziesz je uruchamiał w określonej powłoce, a POSIX wymaga tych poleceń. Coreutils i tak je zapewnia i pomija te, które nie mają żadnego znaczenia poza powłoką.


* Jest to prawie identyczne z odpowiadającym mu tekstem strony podręcznej dla powłoki Almquist , na której opiera się dash, powłoka Almquist Debiana.

** doprowadza zshten pomysł do skrajności: polecenia, które dostajesz, ładując różne moduły zmv, są rzeczami, o których nie pomyślałbyś, że powłoka powinna się w to wniknąć . W tym momencie prawdziwe pytanie brzmi: dlaczego miałbyś używać bash zamiast zsh, który ma wszystkie te wbudowane funkcje?

muru
źródło
1
Okazuje się, że: też nie musi być wbudowany. To głupie, że nie jest wbudowane. Chyba że masz do czynienia z problemami z poziomem dyskietki ratunkowej wczesnego inicjowania (w którym to przypadku odkryłem, że twardy sposób pwd też nie działa niezawodnie) jedyną karą za to, że nie posiadasz tego jako wbudowanego, jest straszna wydajność.
Joshua
5
@Joshua nie, :ponieważ zewnętrzny tak naprawdę nie byłby NOP, nadal będziesz mieć PATHwyszukiwanie, próbę wykonania polecenia itp., Gdy wszystko, czego naprawdę chcesz, to wyraźnie nic nie robić. :jak wbudowane robi to.
muru
2
Bash faktycznie musi pwdbyć wbudowany, aby działał tak, jak działa, z domyślnym zachowaniem pokazującym ścieżkę „logiczną” ( pwd -L). /bin/pwdmoże jedynie zaimplementować pwd -Pzachowanie pokazujące rzeczywiste katalogi nadrzędne, a nie przekierowane przez ciebie dowiązanie symboliczne cd.
Peter Cordes
2
Status @PeterCordes pwdjest nieco zagrożony obecnością PWD, ale tak, jest to również przypadek basha wykorzystującego status wbudowany w celu poprawy funkcjonalności
muru