"Comando non trovato" quando si esegue la funzione sudo da ~ / .zshrc


10

Ho una funzione nel mio ~/.zshrc:

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

La solita invocazione è findPort 3306.

Voglio eseguirlo con privilegi elevati. Ma ottengo "comando non trovato".

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

Presumo che il motivo sia che l'utente root o viene eseguito come shell non interattiva (quindi non si riferisce a un .zshrc) o si riferisce a un altro .zshrc .

Ho visto domande simili in merito alias, ma nessuna domanda riguardante le funzioni definite dall'utente. Le risposte a questo problema riguardano aliasl'aggiunta di un alias a ~/.zshrc:

alias sudo='nocorrect sudo '

O forse:

alias sudo='sudo '

Ho provato entrambe queste soluzioni e il problema persiste (sì, ho riavviato la shell).

Ho anche provato a correre sudo chshper assicurarmi che la mia shell root funzioni sotto zsh. Nessuna di queste soluzioni rimuove il problema "comando non trovato".

C'è un modo per eseguire le mie funzioni definite dall'utente su sudo?


Vedi anche: unix.stackexchange.com/questions/181414/… (non contrassegnato perché zsh ha i suoi trucchi)
muru,

Risposte:


13

sudoesegue i comandi direttamente, non tramite una shell, e anche se ha funzionato una shell per eseguire quel comando, sarebbe una nuova invocazione shell, e non uno che legge i ~/.zshrc(anche se ha iniziato una shell interattiva, sarebbe probabilmente letto root's ~/.zshrc, non tuo a meno che tu non abbia configurato sudoper non reimpostare la $HOMEvariabile).

Qui, dovresti dire sudodi avviare una nuova zshshell e dirlo zshper leggere la tua ~/.zshrcprima di eseguire quella funzione:

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

O:

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

O per condividere le tue attuali funzioni zsh con il nuovo zshinvocato da sudo:

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

Anche se potresti avere un elenco arg troppo lungo se hai definito molte funzioni (come quando usi il sistema di completamento). Quindi potresti voler limitarlo alla findPortfunzione (e ogni altra funzione su cui si basa se presente):

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

Puoi anche fare:

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

Per incorporare il codice della findPortfunzione in una funzione anonima a cui si passa l'argomento 3306. O anche:

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

(lo script inline passato a -c è il corpo della funzione).

È possibile utilizzare una funzione di supporto come:

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

Non usare:

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

Poiché gli argomenti di sdosubirebbero un altro livello di analisi della shell. Confrontare:

$ e() echo "$@"
$ sdo e 'tname;uname'
tname
Linux
$ zsudo e 'tname;uname'
tname;uname

Ho bisogno di una soluzione breve come la digitazione sudo. Sono stato in grado di adattare la tua soluzione di funzione anonima per fare proprio questo. Ho aggiunto la seguente funzione alla mia ~/.zshrc, che è una funzione per eseguire altre funzioni con privilegi elevati:sdo() { sudo zsh -c "(){$functions[$1]} ${@:2}" }
Birchlabs

1
@Birchlabs, vedi modifica
Stéphane Chazelas,

Grazie; Ho aggiornato la mia risposta per utilizzare il collegamento più recente che hai proposto.
Birchlabs,

L'aggiunta della definizione della funzione allo script eseguito tramite sudo è intelligente. Ma non abbastanza intelligente se quella funzione utilizza un'altra funzione (caricata automaticamente o meno).
Damien Flament,

3

Una soluzione molto semplice per me era quella di invocare una shell interattiva usando sudo -s, che sembra funzionare sulla mia versione di zsh in bundle macOS (5.2). Questo mi fornisce le funzioni dal mio ~/.zshrc.

Dalla manpage di sudo, che non accenna davvero a questo comportamento:

-s, --shell
Esegue la shell specificata dalla variabile d'ambiente SHELL se è impostata o la shell specificata dalla voce del database delle password dell'utente che ha invocato. Se viene specificato un comando, viene passato alla shell per l'esecuzione tramite l'opzione -c della shell. Se non viene specificato alcun comando, viene eseguita una shell interattiva.

Non sono sicuro di quale sia il tuo caso d'uso, ma sospetto che tu stia cercando una soluzione interattiva.


Questo funziona davvero. Anche se non è proprio il flusso di lavoro che avevo in mente. Il mio desiderio è di rimanere in un prompt come il mio solito utente, ed elevare solo la mia funzione definita dall'utente myFunc, digitando sudo myFunc- allo stesso modo in cui eleverei qualsiasi processo (come sudo rm -rf .). Questa soluzione eleva il mio intero prompt e tutte le funzioni future, oltre a cambiare il mio utente per tutte le funzioni future, il che è un po 'eccessivo.
Birchlabs,

Il sudo -scomando avvierà un'altra istanza della shell come superutente. Se si esegue quel comando in modo interattivo, la nuova shell sarà interattiva. Ma il comando sudo -s findPort 3306eseguirà il comando findPort 3306nella shell come superutente, quindi uscirà con il codice di stato di quel comando.
Damien Flament,

2

Sono stato in grado di produrre una scorciatoia riutilizzabile per una delle soluzioni descritte nella risposta di Stéphane Chazelas . [Modifica: Stéphane ha ripetuto il collegamento originale che ho proposto; il codice qui descritto è una versione più recente, di sua creazione]

Metti questo nel tuo ~/.zshrc:

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

Ora puoi usare sdocome "solo sudoper funzioni definite dall'utente".

Per confermare che sdofunziona: puoi provarlo con una funzione definita dall'utente che stampa il tuo nome utente.

 birch@server ~/ 🍔 test() whoami

 birch@server ~/ 🍔 test
birch

 birch@server ~/ 🍔 sdo test
root

0

Questo sembra funzionare per me:

function sudo (){
  args="$@"
  /run/wrappers/bin/sudo -u "$USER" zsh -i -c "$args"
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.