Verwenden Sie den Systembefehl anstelle von Bash builtin, ohne den vollständigen Pfad anzugeben

17

Ich verwende Bash als interaktive Shell und frage mich, ob es eine einfache Möglichkeit gibt, Bash dazu zu bringen, einen Systembefehl anstelle eines in die Shell eingebauten Befehls auszuführen, wenn beide denselben Namen haben.

Verwenden Sie beispielsweise das System kill(from util-linux), um die Prozess-ID (pid) der benannten Prozesse zu drucken, anstatt ein Signal zu senden:

$ /bin/kill -p httpd
2617
...

Ohne Angabe des vollständigen Pfads des Systembefehls wird anstelle des Systembefehls der integrierte Bash verwendet. Das killeingebaute Programm hat keine -pOption, daher schlägt der Befehl fehl:

$ kill -p httpd
bash: kill: p: invalid signal specification

Ich habe versucht, die in Make bash aufgelisteten Antworten mit einem externen `time` -Befehl anstatt mit einer eingebauten Shell zu beantworten, aber die meisten funktionieren nur, weil timees sich tatsächlich um ein Shell- Schlüsselwort handelt - nicht um eine eingebaute Shell .

Abgesehen von enable -n killder vorübergehenden Deaktivierung der Bash-Funktion ist die beste Lösung, die ich bisher gesehen habe, Folgendes :

$(which kill) -p httpd

Gibt es andere einfachere (weniger tippende) Möglichkeiten, einen externen Befehl anstelle einer eingebauten Shell auszuführen?

Beachten Sie, dass dies killnur ein Beispiel ist und ich eine verallgemeinerte Lösung möchte , die der Art und Weise ähnelt, in der das commandPräfix mit dem eingebauten Befehl verhindert, dass Funktionen mit demselben Namen wie ein externer Befehl ausgeführt werden. In den meisten Fällen bevorzuge ich in der Regel die integrierte Version, da dadurch ein neuer Vorgang nicht ausgelöst werden kann und in einigen Fällen Funktionen vorhanden sind, die der externe Befehl nicht unterstützt.

Anthony G - Gerechtigkeit für Monica
quelle
Das which killEinfügen von Backticks (kann nicht kommentiert werden) ist etwas kürzer.
abligh
@abligh Guter Punkt. Ich habe jahrelang selbst trainiert, um die "neue" Syntax für die Befehlsersetzung zu verwenden. :)
Anthony G - Gerechtigkeit für Monica
@abligh: Zu Ihrer Information, Sie können Backticks in Kommentare einfügen, indem Sie ihnen Backslashes (\) voranstellen. Aber es gibt Gründe, sich daran zu halten $(…)- sehen Sie dies , dies und das .
G-Man sagt, dass Monica am

Antworten:

20

Vorausgesetzt, es envliegt auf Ihrem Weg:

env kill -p http

envführt die ausführbare Datei mit dem Namen des ersten Arguments in einer (möglicherweise) geänderten Umgebung aus; Als solches kennt oder arbeitet es nicht mit eingebauten Shell-Befehlen.

Dies erzeugt einige Shell Job Control Cruft, ist jedoch nicht auf einen externen Befehl angewiesen:

exec kill -p bash &

execbenötigt eine ausführbare Datei, um die aktuelle Shell zu ersetzen, verwendet also keine eingebauten. Der Job wird im Hintergrund ausgeführt, sodass Sie die gegabelte Hintergrundshell und nicht Ihre aktuelle Shell ersetzen.

chepner
quelle
2
envist eindeutig die richtige Antwort IMHO.
abligh
@abligh: Du hast in meiner gelöschten Antwort Recht. command -p cmdExternen Befehl aufrufen zsh, nicht bash.
Dienstag,
6
(exec kill -p http)Bewirkt, dass der Job eine Sub-Shell anstelle Ihrer aktuellen Shell ersetzt und Sie sich nicht mit der Job-Kontroll-Cruft befassen müssen.
Michael Hoffman
1
@AnthonyGeoghegan Tatsächlich, envweiß aber auch nichts über Shell-Builtins, da es keine Shell ist. Sie würden den gleichen Effekt mit niceoder xargsoder einem anderen Programm wie diesem erzielen .
user253751
1

Der einfachste Weg, um das zu tun, was Sie wollen, könnte darin bestehen, die Linie zu setzen

alias kill="/bin/kill"

in deine ~/.bashrcDatei. Danach interpretiert jeder neue Login / Aufruf von bash "kill" als /bin/kill.

Benjamin Staton
quelle
Ich hatte bereits über einen Alias ​​nachgedacht und dies war eine der Lösungen, die in der Frage aufgeführt sind, auf die ich verwiesen habe, aber ich hoffe auf eine allgemeinere Lösung (ähnlich der commandLösung), anstatt für jeden "schattierten" Befehl einen eigenen Alias ​​zu erstellen. Ich habe jetzt meine Frage bearbeitet, um dies klarer und deutlicher zu machen. In den meisten Fällen bevorzuge ich normalerweise die integrierte Version, da Prozesse durch Job-IDs angegeben werden können. Danke trotzdem.
Anthony G - Gerechtigkeit für Monica
1

Wenn Sie eine Lösung kennen, die eine Eingabe erfordert, und eine Lösung suchen, die weniger Eingaben erfordert, erstellen Sie sie:

runFile() { local cmd="$1"; shift; cmd="$(which "$cmd")" && "$cmd" "$@"; }

Computer zeichnen sich durch die Verkürzung von Dingen aus, die normalerweise einige Anstrengungen erfordern.

PSkocik
quelle
1
Das ist ein guter allgemeiner Punkt, deshalb stimme ich Ihrer Antwort zu. In den letzten Jahren habe ich eine Sammlung von Aliasen, Funktionen und Skripten für die Systeme aufgebaut, die ich regelmäßig verwende. Ich bevorzuge es jedoch, wenn möglich, nicht angepasste Lösungen zu verwenden, da ich manchmal an neuen Installationen oder Servern arbeiten muss, die ich nicht eingerichtet habe. Vielen Dank.
Anthony G - Gerechtigkeit für Monica
1

In diesem speziellen Fall entspricht der Befehl pgrepgenau den Anforderungen.

Im Allgemeinen funktioniert eine Funktion. Von "Dateibefehl":

fcmd(){ local a=$1; shift; $(which "$a") "$@"; }

anrufen als

fcmd kill -p httpd

Wenn Sie jedoch weniger tippen müssen, gibt es keinen kürzeren Weg als einen guten Alias.

Aus dem Konzept "list pid" (lp):

alias lp='/bin/kill -p'

Geben Sie dann einfach Folgendes ein:

lp httpd

quelle
0

(In zsh) Sie können jedem Befehlsnamen ein = -Zeichen voranstellen, um die Systemversion anstelle eines eingebauten Befehls abzurufen. Dies ist auch eine praktische Möglichkeit, Aliasnamen auszuweichen, die ein bestimmtes Szenario durcheinander bringen.

$ =kill -p httpd
Caleb
quelle
1
Ich habe das mit Bash Version 4.3.30 versucht und es hat nicht funktioniert. Ich habe noch nie eine solche Syntax gesehen. Können Sie einen Link hinzufügen, in dem diese Funktion dokumentiert ist? Normalerweise stelle ich einem Alias ​​einen Backslash voran, um die nicht mit Alias ​​versehene Version eines Befehls auszuführen.
Anthony G - Gerechtigkeit für Monica
@Anthony vielleicht ist das zshnur eine sache. Ich benutze es regelmäßig, aber ich werde bashmorgen von einem Computer aus nachsehen.
Caleb,
Ich vermutete, es könnte sich um eine Shell handeln, mit der ich nicht vertraut bin (ich kenne mich nur mit bash, dash und csh aus). Es gab eine andere Antwort (seitdem gelöscht), die nur für funktionierte zsh. Obwohl ich diese Frage mit markiert bashund im Titel verwendet habe, sollten Sie diese Antwort beibehalten, da ein zsh-Benutzer sie dennoch nützlich finden würde.
Anthony G - Gerechtigkeit für Monica
-1

Sie können einen Fehlerbericht zu Ihrer killManpage senden und fragen, warum dies nicht standardmäßige Optionen enthält, die pkillverwendet werden, pkillwenn Sie die Funktionen nutzen möchtenpkill.

Wenn Sie anrufen:

pkill httpd

Sie vermeiden die Probleme, die Sie beschreiben.

schily
quelle