"Befehl nicht gefunden" bei Sudo'ing-Funktion von ~ / .zshrc

10

Ich habe eine Funktion in meinem ~/.zshrc:

findPort() {
    lsof -t -i :$1
}

Der übliche Aufruf ist findPort 3306.

Ich möchte es mit erhöhten Rechten ausführen. Aber ich bekomme "Befehl nicht gefunden".

  git 🍔 sudo findPort 3306
sudo: findPort: command not found

Ich nehme an, der Grund dafür ist, dass der Root-Benutzer entweder als nicht interaktive Shell ausgeführt wird (bezieht sich also nicht auf eine .zshrc-Datei) oder auf eine andere .zshrc .

Ich habe ähnliche Fragen bezüglich alias, aber keine Frage bezüglich benutzerdefinierter Funktionen gesehen. Die Antworten auf dieses Problem betreffen aliasdas Hinzufügen eines Alias ​​zu ~/.zshrc:

alias sudo='nocorrect sudo '

Oder vielleicht:

alias sudo='sudo '

Ich habe beide Lösungen ausprobiert und das Problem besteht immer noch (ja, ich habe die Shell neu gestartet).

Ich habe auch versucht, auszuführen, sudo chshum sicherzustellen, dass meine Root-Shell unter läuft zsh. Keine dieser Lösungen behebt das Problem "Befehl nicht gefunden".

Gibt es eine Möglichkeit, meine benutzerdefinierten Funktionen unter sudo auszuführen?

Birchlabs
quelle
Siehe auch: unix.stackexchange.com/questions/181414/… (nicht markiert, weil zsh seine eigenen Tricks hat)
muru

Antworten:

13

sudoführt Befehle direkt aus, nicht über eine Shell, und selbst wenn eine Shell ausgeführt würde, um diesen Befehl auszuführen, wäre dies ein neuer Shell-Aufruf und kein Aufruf, der Ihren liest ~/.zshrc(selbst wenn eine interaktive Shell gestartet würde, würde er wahrscheinlich roots lesen ~/.zshrc, nicht Ihre, es sei denn, Sie haben konfiguriert sudo, dass die $HOMEVariable nicht zurückgesetzt wird).

Hier müssen Sie angeben, dass sudoeine neue zshShell gestartet werden soll , und dies mitteilen, zshum Ihre zu lesen, ~/.zshrcbevor Sie diese Funktion ausführen:

sudo zsh -c '. $0; "$@"' ~/.zshrc findPort 3306

Oder:

sudo zsh -c '. $0; findPort 3306' ~/.zshrc

Oder um Ihre aktuellen zsh-Funktionen mit den neuen Funktionen zu teilen, die zshaufgerufen werden von sudo:

sudo zsh -c "$(functions); findPort 3306"

Wenn Sie viele Funktionen definiert haben (z. B. bei Verwendung des Vervollständigungssystems), wird möglicherweise eine zu lange Argumentliste angezeigt . Sie können es also auf die findPortFunktion beschränken (und auf jede andere Funktion, auf die es sich stützt, falls vorhanden):

sudo zsh -c "$(functions findPort); findPort 3306"

Sie könnten auch tun:

sudo zsh -c "(){$functions[findPort]} 3306"

Einbetten des findPortFunktionscodes in eine anonyme Funktion, an die Sie das Argument 3306 übergeben. Oder auch:

sudo zsh -c "$functions[findPort]" findPort 3306

(Das übergebene Inline-Skript -c ist der Hauptteil der Funktion).

Sie könnten eine Hilfsfunktion verwenden wie:

zsudo() sudo zsh -c "$functions[$1]" "$@"

Verwende nicht:

sdo () {sudo zsh -c "() {$ functions [$ 1]} $ {@: 2}"}

Da würden die Argumente von sdoeine andere Ebene der Shell-Analyse durchlaufen. Vergleichen Sie:

$ e() echo "$@"
$ sdo e 'tname;uname'
tname
Linux
$ zsudo e 'tname;uname'
tname;uname
Stéphane Chazelas
quelle
Ich brauche eine Lösung, die so kurz wie das Tippen ist sudo. Ich konnte Ihre anonyme Funktionslösung anpassen , um genau das zu tun. Ich habe die folgende Funktion zu meiner hinzugefügt ~/.zshrc, die eine Funktion ist, um andere Funktionen mit erhöhten Berechtigungen sdo() { sudo zsh -c "(){$functions[$1]} ${@:2}" }
auszuführen
1
@ Birchlabs, siehe bearbeiten
Stéphane Chazelas
Vielen Dank; Ich habe meine Antwort aktualisiert, um die neuere Verknüpfung zu verwenden, die Sie vorgeschlagen haben.
Birchlabs
Das Hinzufügen der Funktionsdefinition zu dem über sudo ausgeführten Skript ist klug. Aber nicht klug genug, wenn diese Funktion eine andere Funktion verwendet (automatisch geladen oder nicht).
Damien Flament
3

Eine sehr einfache Lösung für mich war das Aufrufen einer interaktiven Shell mit sudo -s, die anscheinend auf meiner mit macOS gebündelten Version von zsh (5.2) funktioniert. Dies bietet mir die Funktionen von meinem ~/.zshrc.

Aus der Sudo-Manpage, die dieses Verhalten nicht wirklich andeutet:

-s, --shell Führt
die von der Umgebungsvariablen SHELL angegebene Shell aus, wenn sie festgelegt ist, oder die Shell, die durch den Kennwortdatenbankeintrag des aufrufenden Benutzers angegeben wird. Wenn ein Befehl angegeben wird, wird er zur Ausführung über die Option -c der Shell an die Shell übergeben. Wenn kein Befehl angegeben wird, wird eine interaktive Shell ausgeführt.

Ich bin mir nicht sicher, was Ihr Anwendungsfall ist, aber ich vermute, Sie suchen nach einer interaktiven Lösung.

jhat
quelle
Das funktioniert tatsächlich. Obwohl es nicht ganz der Workflow ist, den ich mir vorgestellt habe. Mein Wunsch ist es, als normaler Benutzer in einer Eingabeaufforderung zu bleiben und nur meine benutzerdefinierte Funktion myFuncdurch Eingabe zu sudo myFuncerhöhen - genauso wie ich jeden Prozess (wie sudo rm -rf .) erhöhen würde . Diese Lösung erhöht meine gesamte Eingabeaufforderung und alle zukünftigen Funktionen und ändert meinen Benutzer für alle zukünftigen Funktionen - was ein bisschen übertrieben ist.
Birchlabs
Der sudo -sBefehl startet eine weitere Instanz Ihrer Shell als Superuser. Wenn Sie diesen Befehl interaktiv ausführen, ist Ihre neue Shell interaktiv. Der Befehl sudo -s findPort 3306führt den Befehl jedoch findPort 3306in Ihrer Shell als Superuser aus und beendet ihn mit dem Statuscode dieses Befehls.
Damien Flament
2

Ich konnte eine wiederverwendbare Abkürzung für eine der in Stéphane Chazelas ' Antwort beschriebenen Lösungen erstellen . [Bearbeiten: Stéphane hat die von mir vorgeschlagene ursprüngliche Verknüpfung wiederholt. Der hier beschriebene Code ist eine neuere Version seiner Herstellung.]

Setzen Sie dies in Ihre ~/.zshrc:

sdo() sudo zsh -c "$functions[$1]" "$@"

Jetzt können Sie sdoals "nur sudofür benutzerdefinierte Funktionen" verwenden.

Um zu bestätigen, dass dies sdofunktioniert: Sie können es mit einer benutzerdefinierten Funktion ausprobieren, die Ihren Benutzernamen druckt.

 birch@server ~/ 🍔 test() whoami

 birch@server ~/ 🍔 test
birch

 birch@server ~/ 🍔 sdo test
root
Birchlabs
quelle
0

Das scheint bei mir zu funktionieren:

function sudo (){
  args="$@"
  /run/wrappers/bin/sudo -u "$USER" zsh -i -c "$args"
}
Chris Stryczynski
quelle