Ich verstehe, dass der Befehl command
angegeben ist inneuester POSIX-Standardund builtin
ist nicht. Mir ist auch klar, dass beide Befehlereguläre eingebaute(d. h. sie können durch benutzerdefinierte Funktionen überschrieben werden). Einige Shells definieren builtin
, aber nicht alle (z. B. dash
nicht). Ich möchte verstehen, warum builtin
in einigen Shells eingeführt wurde.
Nach meinem besten Verständnis builtin
werden erst spezielle und dann normale integrierte Funktionen zurückgegeben, aber erst command
spezielle integrierte Funktionen, dann normale integrierte Funktionen und dann Befehle im Pfad (und der -p
Schalter kann mit verwendet werden, command
um anzugeben, dass die von der Shell definierte Vorgabe verwendet werden soll $PATH
, falls der Benutzer die geändert hat $PATH
).
In sehe ich beispielsweise mksh
Folgendes:
(NOTIZ: mksh
auf Ubuntu 20.04 aus Repo installiert http://archive.ubuntu.com/ubuntu focal/universe amd64 mksh amd64 58-1
)
$ echo $KSH_VERSION
@(#)MIRBSD KSH R58 2020/03/27
$ which -a echo
/usr/bin/echo
/bin/echo
$ which -a printf
/usr/bin/printf
/bin/printf
$ type echo
echo is a shell builtin
$ type printf
printf is /usr/bin/printf
$ command echo 'Hello World!'
Hello World!
$ command printf 'Hello World!\n'
Hello World!
$ builtin echo 'Hello World!'
Hello World!
$ builtin printf 'Hello World!\n'
mksh: builtin: printf: not found
$ sudo cp /usr/bin/printf /usr/bin/printf.backup
$ sudo cp /bin/printf /bin/printf.backup
$ sudo rm /usr/bin/printf
$ sudo rm /bin/printf
rm: cannot remove '/bin/printf': No such file or directory
$ sudo cp /usr/bin/printf.backup ~/printf
$ echo $PATH | sed 's/:/\n/g'
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
# ...remainder ommitted here for brevity
$ export PATH=~:$PATH
$ echo $PATH | sed 's/:/\n/g'
/home/my_username
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
# ...remainder ommitted here for brevity
$ command printf 'Hello World!\n'
Hello World!
$ command -p printf 'Hello World!\n'
mksh: printf: inaccessible or not found
Habe ich das richtig verstanden? Oder sind do command
und builtin
do genau dasselbe (und wenn ja, warum wurde es builtin
eingeführt?)? Oder gibt es einen weiteren subtilen Unterschied zwischen command
und builtin
?
(Ich habe versucht, auf StackExchange nach einer Antwort zu suchen, aber nichts gefunden. Wenn mir also jemand eine passende Antwort zeigen könnte, wäre ich sehr dankbar.)
AKTUALISIEREN:
Es ist auch erwähnenswert, dass command
und builtin
die Suche nach und Verwendung definierter Aliase „überspringen“. Die Aliaserweiterung erfolgt in der Auswertungsreihenfolge der POSIX-Shell vor der Befehlssuche und -auswertung, ebenso wie die Erweiterung von Arithmetik-, Variablen- und Datei-Platzhaltern. Arithmetik-, Variablen- und Platzhalter werden jedoch innerhalb von command
und ausgewertet builtin
, Aliase jedoch nicht. Das scheint etwas zu sein, was in den Dokumenten erwähnt werden sollte.
Zum Beispiel:
$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ command echo $((1 + 1))
2
$ builtin echo $((3 + 1))
4
Aber
$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ alias \[='echo hello'
$ [
hello
$ if builtin [ 'north' != 'south' ]; then echo 'what a world!'; fi
what a world!
UPDATE 2:
Ich denke, es ist auch erwähnenswert, dass ich nach einigem Graben und Experimentieren herausgefunden habe, dass zsh
sich verhältDAS KOMPLETTE GEGENTEILdes POSIX-Standards und anderer Shells im Bourne-Stil in Bezug auf den command
Befehl.
Von demzsh-Dokumente(Abschnitt 6.2, Präbefehlsmodifizierer)
Befehl [-pvV]
Das Befehlswort wird als Name eines externen Befehls und nicht als einer Shell-Funktion oder eines integrierten Befehls betrachtet.
Zum Beispiel
$ echo ${ZSH_VERSION}
5.8
$ command cd ~
zsh: command not found: cd
$ command -p cd ~
zsh: command not found: cd
$ command echo 'hi'
hi
# `echo` is a regular builtin just like `cd` though...??!!!
$ set -o |grep posix
posixaliases off
posixargzero off
posixbuiltins off
posixcd off
posixidentifiers off
posixjobs off
posixstrings off
posixtraps off
$ cd() { echo 'I told you.'; }
$ cd
I told you.
# ????!!!!
Nur wenn die POSIX_BUILTINS
Umgebungsvariable gesetzt ist (verwenden Sie set -o posixbuiltins
), führt der Befehl command
auch spezielle und reguläre Built-Ins aus.
Zum Beispiel
$ echo ${ZSH_VERSION}
5.8
$ cd /
$ ls
bin dev home lib lib64 lost+found mnt proc run snap sys usr
boot etc init lib32 libx32 media opt root sbin srv tmp var
$ set -o posixbuiltins
$ command cd ~
$ ls
Desktop Downloads Pictures Templates
Documents Music Public Videos
$ command -p cd /
$ ls
bin dev home lib lib64 lost+found mnt proc run snap sys usr
boot etc init lib32 libx32 media opt root sbin srv tmp var
Auf der anderen Seite, von derBash-Dokumente
Befehl
Befehl [-pVv]Befehl [Argumente …]Führt den Befehl mit Argumenten aus und ignoriert dabei alle Shell-Funktionen mit dem Namen „Befehl“. Es werden nur in der Shell integrierte Befehle oder Befehle ausgeführt, die durch Durchsuchen des Pfads gefunden wurden.
Zum Beispiel
$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ cd /
$ ls
bin dev home lib lib64 lost+found mnt proc run snap sys usr
boot etc init lib32 libx32 media opt root sbin srv tmp var
$ set +o posix # Turn off POSIX mode
$ command cd ~
$ ls
Desktop Downloads Pictures Templates
Documents Music Public Videos
$ command -p cd /
$ ls
bin dev home lib lib64 lost+found mnt proc run snap sys usr
boot etc init lib32 libx32 media opt root sbin srv tmp var
So zsh
verhält sichDAS KOMPLETTE GEGENTEILanderer Shells im Bourne-Stil in Bezug auf den command
Befehl ... Ich fange an, sie zsh
immer weniger zu mögen ... Käufer aufgepasst (Vorbehalt beim Kauf) Ich nehme an.
UPDATE 3:
Es ist auch erwähnenswert, dass kein integrierter Befehl ksh88
vorhanden ist . Dieser wurde in eingeführt . Um einen integrierten Befehl in zu ersetzen , müssten Sie eine umständliche Kombination aus Aliasing, Funktionen und Anführungszeichen verwenden.command
ksh93
ksh88
(Quelle: Robbins, Arnold; Rosenblatt, Bill. Learning the Korn Shell: Unix Programming (S. 456). O'Reilly Media. Kindle-Ausgabe.)
Dies steht im Einklang mit der Antwort von @Gilles: „Also, hör auf, böse zu sein.“
Antwort1
DerPOSIX-Begründung fürcommand
beantwortet die meisten historischen Aspekte Ihrer Frage.
DerBefehlDienstprogramm ist etwas ähnlich der Eighth Edition ShelleingebautBefehl, aber daBefehlgeht auch in das Dateisystem, um nach Dienstprogrammen zu suchen, der Nameeingebautwäre nicht intuitiv.
(…) DerBefehl -vUnd-VEs wurden Optionen hinzugefügt, um die Anforderungen der Benutzer zu erfüllen, die derzeit von drei verschiedenen historischen Dienstprogrammen erfüllt werden:Typin der System V-Shell,woherin der KornShell undwelchein der C-Shell.
ImAchte Ausgabe shwurde das builtin
integrierte Feature als bloßes Umgehen von Funktionen dokumentiert:
Führen Sie den integrierten Sonderbefehl (z. B. „break“) unabhängig von Funktionen aus, die mit demselben Namen definiert sind.
Aliase gab es noch nicht (und als sie auftauchten, gab es verschiedene Mechanismen, um sie zu umgehen). Wenn Sie eine Funktion umgehen wollten, um einen externen Befehl auszuführen, konnten Sie ihren vollständigen Pfad angeben, was den Vorteil hatte, genau anzugeben, was Sie ausführen wollten, falls sich mehrere ausführbare Dateien mit diesem Namen im Befehlssuchpfad befanden. Portabilität zwischen Systemen, bei denen der vollständige Pfad zu einem Befehl unterschiedlich sein könnte, war kein weit verbreitetes Anliegen. Das Gleiche builtin
galt für die eine Sache, die nicht wirklich anders gemacht werden konnte.
Später kam POSIX und fügte eine Standardmethode zum Umgehen einer Funktion hinzu. In diesem Zusammenhang war die Portabilität auf Systeme, auf denen sich externe Befehle an anderen Orten befanden, ein großes Anliegen und reichte daher builtin
nicht aus. Daher das neue , command
das Funktionen (und Aliase, da es an eine Stelle command foo
stellt foo
, an der Aliase nicht erweitert werden) umgeht und Standardbefehle findet. (Außerdem hat ksh heute ein integriertes Element namens , builtin
das etwas völlig anderes macht, aber ich weiß nicht, ob es vor oder nach der Erstellung von durch POSIX kam command
.) Überspringt jedoch command
absichtlich keine integrierten Befehle, auch hier aus Portabilitätsgründen: Wenn ein sh-Programm einen Standardbefehl aufruft, entscheidet das Betriebssystem, ob dieser Befehl als integriertes Element bereitgestellt wird. command
hebt das „spezielle integrierte“ Verhalten spezieller integrierter Befehle auf, damit die Anwendung wieder nicht wissen muss, ob sie ein integriertes Element aufruft oder nicht.
Ich weiß nicht, warum zsh command
Builtins umgeht, wenn es sich nicht im POSIX-Modus befindet (insbesondere, wenn dieposix_builtins
Möglichkeitist nicht gesetzt). Die aktuelle Implementierung command
geht auf eine Änderung im Mai 1996 zurück, die inzsh 2.6 Beta 20(„-, exec, noglob und command aus der Liste der reservierten Wörter entfernen“). Da diese Implementierung bereits eine andere Handhabung für den POSIX-Modus hatte, gehe ich davon aus, dass dies der Abwärtskompatibilität mit einer früheren Version von zsh diente, habe dies aber nicht weiter untersucht. Es könnte Absicht sein, denn wenn posix_builtins
nicht gesetzt, sind integrierte Funktionen nicht unbedingt mit POSIX kompatibel und es ist daher am besten, sie nicht aufzurufen, wenn eine Anwendung den speziellen POSIX-Befehl verwendet command
.