Warum gibt es ein / bin / echo und warum sollte ich es verwenden wollen?

52

Ich habe festgestellt, dass /bin/echoauf meinem Ubuntu MATE 17.04-System eine ausführbare Binärdatei vorhanden ist .

Ich dachte, das ist seltsam, weil

$ type echo
echo is a shell builtin

/bin/echoKurztests legen nahe, dass dies dasselbe wie das in Bash eingebaute Verfahren bewirkt echo:

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

Also, warum gibt es eine andere Version des echoBash-Programms, und warum oder wann würde ich es verwenden wollen?

Zanna
quelle
2
@ bodhi.zazen Das ist ziemlich nützlich, auch wenn es nicht dasselbe ist, weil es das Gegenteil dieser Frage anspricht. Bei dieser Frage wird gefragt, warum echosie als eingebaute Shell bereitgestellt wird, während bei dieser Frage gefragt wird, warum sie als externer Befehl bereitgestellt wird.
Eliah Kagan
3
Ein Grund ist, dass nicht jeder bash benutzt. Ich würde vermuten, dass / bin / echo älter ist als bash, und die Entwickler fanden es nützlich / effizient, es als eingebautes einzuschließen, anstatt die ausführbare Datei zu verwenden.
Jamesqf

Antworten:

87

Wenn Sie eine bashEingabeaufforderung öffnen und einen echoBefehl eingeben , wird eine eingebaute Shell verwendet, anstatt sie auszuführen/bin/echo . Die Gründe, warum es immer noch wichtig ist /bin/echozu existieren, sind:

  1. Sie verwenden nicht immer eine Shell. Unter verschiedenen Umständen führen Sie eine ausführbare Datei direkt und nicht über eine Shell aus.
  2. Zumindest theoretisch haben einige Shells keine echoeingebauten. Dies ist eigentlich nicht erforderlich.

Nehmen wir an, Sie möchten alle regulären Dateien, deren Namen mit abcirgendwo in beginnen src, verschieben, um die Nummer 1 zu erweitern dest. Es gibt mehrere Möglichkeiten, dies zu tun, aber eine davon ist:

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

Angenommen, Sie möchten nicht nur diesen Befehl ausführen, sondern jeden Befehl anzeigen, der zuerst ausgeführt wird. Nun, dann können Sie echodem Befehl genau wie in anderen Kontexten voranstellen :

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

Benutzt findaber keine Shell. Das läuft /bin/echo.

Außer findmit -execoder-execdir wird die /bin/echoausführbare Datei von anderen Programmen aufgerufen, die selbst Programme ausführen, jedoch nicht über eine Shell. Dies geschieht mit dem xargsBefehl (der bezieht sich auf find), sowie in einer Reihe von anderen Zusammenhängen, wie beispielsweise die Exec=Leitung von einer .desktopDatei . Ein anderes Beispiel ist, wenn Sie ausführen sudo echo, was nützlich sein kann, um zu testen, ob sudoes funktioniert.

Ebenso haben einige Muscheln einen printfeingebauten, /usr/bin/printfexistieren aber auch.

Ein weniger häufiger möglicher Grund, den Sie absichtlich verwenden könnten, /bin/echoist, wenn Sie sich auf die Unterschiede zwischen dem echoBefehl und dem Befehl verlassen, der von Ihrer Shell bereitgestellt wird. man echoDokumente /bin/echo; help echoin bash dokumenten das basheingebaute. echoist nicht sehr portabel, da unterschiedliche Implementierungen - sowohl auf Betriebssystemen als auch auf Shells auf demselben Betriebssystem - unterschiedliche Optionen (z. B. -e) unterstützen und sich in der Behandlung von Backslashes unterscheiden . Natürlich ist es besser, sich nicht auf solche Details zu verlassen, printfsondern diese zu verwenden, da sie weitaus portabler sind .

In bashkönnen Sie die typeeingebaute Show ebenfalls erstellen /bin/echo- vorausgesetzt, sie /binist in Ihrer, $PATHwie es immer sein sollte - indem Sie ihr die -aFlagge übergeben :

$ type -a echo
echo is a shell builtin
echo is /bin/echo
Eliah Kagan
quelle
21
Und auch, weil die POSIX-Spezifikation besagt, dass es eine geben muss.
Glenn Jackman
4
@glennjackman Ich hatte gehofft, jemand würde eine Antwort dazu posten, und ich hoffe, Sie entscheiden sich dafür! Es gibt jedoch einige Feinheiten, da weder Debian, Ubuntu, noch GNU Coreutils (noch das GNU-Projekt insgesamt) versuchen, POSIX in allem zu befolgen . Beispielsweise besteht POSIX daraufcd , dass eine ausführbare Datei vorhanden ist (die beim Ausführen das Verzeichnis ändert und beendet und den Aufrufer an der Stelle belässt, an der er sich zuvor befunden hat), und einige Betriebssysteme verfügen über eine solche Datei . Es kann hilfreich sein, 4.1 in den GNU-Standards zu zitieren .
Eliah Kagan
@EliahKagan: Incidentaly / usr / bin / cd hat den folgenden Verwendungszweck: / usr / bin / cd Verzeichnisbefehl führt diesen Befehl in diesem Verzeichnis aus. Wenn der Verzeichniswechsel fehlschlägt, startet der Befehl nicht.
Joshua
4
@Joshua eine bessere Verwendung cdist einfach ein Test der Fähigkeit, auf ein bestimmtes Verzeichnis zuzugreifen: Wenn dies /usr/bin/cd some/direrfolgreich ist, haben Sie in einer Aufnahme Folgendes getestet: a) das some/direxistiert, b) dass es sich um ein Verzeichnis oder einen Link zu einem Verzeichnis handelt, und c) das Erforderliche Berechtigungen für den Zugriff auf dieses Verzeichnis sind vorhanden. alles ohne deinen eigenen Zustand zu ändern.
Muru
1
@CarlWitthoft, siehe Warum ist printf besser als echo? Dies ist /bin/echoauch nicht der \bin\echoFall, es sei denn, Sie verwenden Windows. ;)
Wildcard
31

Eliah hat das sehr gut beantwortet, aber ich möchte einen Kommentar zum Teil "Warum gibt es eine andere Version von echogetrennt vom Bash-Programm?" Abgeben. Das ist die falsche Frage.

Die richtige Frage ist: Warum ist dies überhaupt ein eingebautes Kommando, wenn es ein perfektes externes Kommando gewesen sein könnte (und ist)?

Werfen Sie der Einfachheit halber einen Blick auf die Builtins in dash, a measly 38 (bash hat zum Vergleich 61, basierend auf der Ausgabe von 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

Wie viele davon müssen eingebaut werden? [, echo, false, printf, pwd, test, Und truenicht braucht builtins zu sein: Sie tun nichts , die nur ein builtin tun kann (beeinflussen oder Shell - Zustand erhalten, die auf externe Befehle nicht verfügbar ist). Bashs printfnutzt zumindest den Vorteil, dass es ein integriertes Element ist: printf -v varSpeichert die Ausgabe in der Variablen var. timein bash ist auch etwas Besonderes: Indem Sie ein Schlüsselwort sind, können Sie beliebige Befehlslisten in bash zeitlich festlegen (Bindestrich hat kein timeÄquivalent). pwdEs muss auch kein integrierter Befehl sein - jeder externe Befehl erbt das aktuelle Arbeitsverzeichnis (und es ist auch ein externer Befehl ).:ist eine Ausnahme - Sie brauchen eine NOP, und :ist es. Der Rest führt Aktionen aus, die ein externer Befehl problemlos ausführen kann.

Ein Fünftel dieser Buildins müssen also keine Buildins sein. Warum dann? Die dashManpage * erklärt im Nachhinein, warum es sich um Builtins handelt (Schwerpunkt Mine):

Builtins
 Dieser Abschnitt listet die eingebauten Befehle auf, die aufgrund ihrer Eigenschaften eingebaut sind
 Sie müssen einen Vorgang ausführen, der nicht von einem anderen ausgeführt werden kann
 Prozess. Zusätzlich zu diesen gibt es möglicherweise mehrere andere Befehle
 Aus Effizienzgründen eingebaut sein (z. B. printf (1), echo (1), test (1) usw.).

Das ist so ziemlich alles: Diese integrierten Funktionen sind vorhanden, weil sie so häufig, interaktiv und in Skripten verwendet werden und ihre Funktionalität so einfach ist, dass die Shell die Aufgabe übernehmen kann. Und so geschieht es: einige (? Die meisten) Muscheln auf dem Job nahm ** gehen. Diesh von 2.9 BSD , und Sie werden keine finden echobuiltin.

Es ist also durchaus möglich, dass eine minimale Shell die Implementierung von Befehlen wie builtins überspringt (ich glaube jedoch, dass dies bei keiner aktuellen Shell der Fall ist). Das GNU-Coreutils-Projekt geht nicht davon aus, dass Sie sie in einer bestimmten Shell ausführen werden, und POSIX benötigt diese Befehle. Coreutils stellt diese also trotzdem zur Verfügung und überspringt diejenigen, die außerhalb der Shell keine Bedeutung haben.


* Dies ist fast identisch mit dem entsprechenden Manpage-Text für die Almquist-Shell , auf der dash, die Debian-Almquist-Shell, basiert.

** zshbringt diese Idee auf das Äußerste: Die Befehle, die Sie beim Laden verschiedener Module erhalten zmv, sind Dinge, von denen Sie nicht glauben, dass sie für eine Shell überhaupt erforderlich sind . Zu diesem Zeitpunkt lautet die eigentliche Frage: Warum sollten Sie bash anstelle von zsh verwenden, das all diese eingebauten Funktionen hat?

muru
quelle
1
Es stellt sich heraus, dass: auch kein Builtin sein muss. Es ist nur dumm, dass es kein eingebauter ist. Es sei denn, Sie haben mit frühen Problemen auf der Ebene der Init-Rettungsdisketten zu tun (in diesem Fall habe ich festgestellt, dass pwd auf die harte Tour auch nicht zuverlässig funktioniert).
Joshua
5
@Joshua nein, :da ein Externer nicht wirklich ein NOP wäre, hätten Sie immer noch eine PATHSuche, einen Versuch, den Befehl auszuführen usw., wenn alles, was Sie wirklich wollen, darin besteht, ausdrücklich nichts zu tun. :als eingebauter macht das.
muru
2
Bash muss tatsächlich pwdeingebaut sein, damit es so funktioniert, mit dem Standardverhalten, dass der "logische" Pfad ( pwd -L) angezeigt wird . /bin/pwdkonnte nur das pwd -PVerhalten des Anzeigens der tatsächlichen übergeordneten Verzeichnisse implementieren , nicht des Symlinks, den Sie cddurchlaufen haben.
Peter Cordes
2
@PeterCordes pwd'Status wird durch das Vorhandensein von etwas beeinträchtigt PWD, aber ja, das ist auch eine Instanz von Bash, die den eingebauten Status verwendet, um die Funktionalität zu verbessern
muru