«Commande introuvable» lors de la fonction sudo de ~ / .zshrc


10

J'ai une fonction dans mon ~/.zshrc:

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

L'invocation habituelle est findPort 3306.

Je veux l'exécuter avec des privilèges élevés. Mais j'obtiens "commande introuvable".

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

Je suppose que la raison en est que l'utilisateur root s'exécute en tant que shell non interactif (ne fait donc pas référence à un .zshrc) ou fait référence à un autre .zshrc .

J'ai vu des questions similaires concernant alias, mais aucune question concernant les fonctions définies par l'utilisateur. Les réponses à ce problème concernant l' aliasajout d'un alias à ~/.zshrc:

alias sudo='nocorrect sudo '

Ou peut-être:

alias sudo='sudo '

J'ai essayé ces deux solutions, et le problème existe toujours (oui, j'ai relancé le shell).

J'ai également essayé de courir sudo chshpour m'assurer que mon shell racine fonctionne sous zsh. Aucune de ces solutions ne supprime le problème «commande introuvable».

Existe-t-il un moyen d'exécuter mes fonctions définies par l'utilisateur sous sudo?


Voir aussi: unix.stackexchange.com/questions/181414/… (ne signalant pas parce que zsh a ses propres astuces)
muru

Réponses:


13

sudoexécute des commandes directement, sans passer par un obus, et même si elle a couru un shell pour exécuter cette commande, ce serait une nouvelle invocation shell, et non celui qui lit votre ~/.zshrc(même si elle a commencé un shell interactif, il a probablement lu root« s ~/.zshrc, pas le vôtre, sauf si vous avez configuré sudopour ne pas réinitialiser la $HOMEvariable).

Ici, vous auriez besoin de dire sudode démarrer un nouveau zshshell, et de le dire zshpour lire votre ~/.zshrcavant d'exécuter cette fonction:

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

Ou:

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

Ou pour partager vos fonctions zsh actuelles avec la nouvelle zshinvoquée par sudo:

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

Bien que vous puissiez obtenir une erreur de liste d'arguments trop longue si vous avez défini de nombreuses fonctions (comme lors de l'utilisation du système de complétion). Donc, vous voudrez peut-être le limiter à la findPortfonction (et à toute autre fonction sur laquelle il s'appuie le cas échéant):

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

Vous pourriez également faire:

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

Pour incorporer le code de la findPortfonction dans une fonction anonyme à laquelle vous passez l'argument 3306. Ou même:

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

(le script en ligne transmis à -c est le corps de la fonction).

Vous pouvez utiliser une fonction d'assistance comme:

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

Ne pas utiliser:

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

Comme les arguments de sdosubiraient un autre niveau d'analyse du shell. Comparer:

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

J'ai besoin d'une solution aussi courte que de taper sudo. J'ai pu adapter votre solution de fonction anonyme pour cela. J'ai ajouté la fonction suivante à ma ~/.zshrc, qui est une fonction pour exécuter d' autres fonctions avec des privilèges élevés:sdo() { sudo zsh -c "(){$functions[$1]} ${@:2}" }
Birchlabs

1
@Birchlabs, voir edit
Stéphane Chazelas

Merci; J'ai mis à jour ma réponse pour utiliser le nouveau raccourci que vous avez proposé.
Birchlabs

Ajouter la définition de fonction au script exécuté via sudo est intelligent. Mais pas assez intelligent si cette fonction utilise une autre fonction (chargée automatiquement ou non).
Damien Flament

3

Une solution très simple pour moi a été d'invoquer un shell interactif utilisant sudo -s, qui semble fonctionner sur ma version de macsh intégrée à zsh (5.2). Cela me fournit les fonctions de mon ~/.zshrc.

Depuis la page de manuel sudo, qui ne fait pas vraiment allusion à ce comportement:

-s, --shell
Exécute le shell spécifié par la variable d'environnement SHELL s'il est défini ou le shell spécifié par l'entrée de la base de données de mots de passe de l'utilisateur appelant . Si une commande est spécifiée, elle est transmise au shell pour exécution via l'option -c du shell. Si aucune commande n'est spécifiée, un shell interactif est exécuté.

Je ne sais pas quel est votre cas d'utilisation, mais je soupçonne que vous recherchez une solution interactive.


Cela fonctionne effectivement. Bien que ce ne soit pas tout à fait le flux de travail que j'avais en tête. Mon désir est de rester dans une invite comme mon utilisateur habituel, et d'élever juste ma fonction définie myFuncpar l' utilisateur , en tapant sudo myFunc- de la même manière que j'élèverais n'importe quel processus (comme sudo rm -rf .). Cette solution élève toute mon invite et toutes les fonctions futures, ainsi que de changer mon utilisateur pour toutes les fonctions futures - ce qui est un peu exagéré.
Birchlabs

La sudo -scommande lancera une autre instance de votre shell en tant que superutilisateur. Si vous exécutez cette commande de manière interactive, votre nouveau shell sera interactif. Mais la commande sudo -s findPort 3306exécutera la commande findPort 3306dans votre shell en tant que superutilisateur, puis quittera avec le code d'état de cette commande.
Damien Flament

2

J'ai pu produire un raccourci réutilisable pour l'une des solutions décrites dans la réponse de Stéphane Chazelas . [Edit: Stéphane a réitéré le raccourci original que j'ai proposé; le code décrit ici est une version plus récente de sa création]

Mettez ceci dans votre ~/.zshrc:

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

Vous pouvez maintenant l'utiliser sdocomme " sudopour les fonctions définies par l'utilisateur uniquement".

Pour confirmer que cela sdofonctionne: vous pouvez l'essayer sur une fonction définie par l'utilisateur qui imprime votre nom d'utilisateur.

 birch@server ~/ 🍔 test() whoami

 birch@server ~/ 🍔 test
birch

 birch@server ~/ 🍔 sdo test
root

0

Cela semble fonctionner pour moi:

function sudo (){
  args="$@"
  /run/wrappers/bin/sudo -u "$USER" zsh -i -c "$args"
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.