„Polecenie nie znaleziono” podczas funkcji sudo z ~ / .zshrc

10

Mam funkcję w moim ~/.zshrc:

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

Zwykłe wywołanie to findPort 3306.

Chcę uruchomić go z podwyższonymi uprawnieniami. Ale dostaję „polecenie nie znaleziono”.

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

Zakładam, że powodem jest to, że użytkownik root albo działa jako nieinteraktywna powłoka (dlatego nie odnosi się do .zshrc), albo odnosi się do innej .zshrc .

Widziałem podobne pytania dotyczące alias, ale nie ma pytań dotyczących funkcji zdefiniowanych przez użytkownika. Odpowiedzi na ten problem aliasdotyczą dodania aliasu do ~/.zshrc:

alias sudo='nocorrect sudo '

A może:

alias sudo='sudo '

Wypróbowałem oba te rozwiązania, a problem nadal występuje (tak, ponownie uruchomiłem powłokę).

Próbowałem także uruchomić, sudo chshaby upewnić się, że moja powłoka root działa zsh. Żadne z tych rozwiązań nie usuwa problemu „nie znaleziono polecenia”.

Czy istnieje sposób uruchamiania moich funkcji zdefiniowanych przez użytkownika w sudo?

Brzozy
źródło
Zobacz także: unix.stackexchange.com/questions/181414/… (nie oflaguje się, ponieważ zsh ma swoje własne sztuczki)
muru

Odpowiedzi:

13

sudouruchamia polecenia bezpośrednio, a nie za pomocą powłoki, a nawet jeśli prowadził powłoki do uruchomienia tej komendy, że będzie to nowa powłoka wezwanie, a nie taki, który czyta swoje ~/.zshrc(nawet jeśli to się zaczęło interaktywną powłokę, będzie to prawdopodobnie odczytać root„s ~/.zshrc, nie twój, chyba że skonfigurowano, sudoaby nie resetować $HOMEzmiennej).

Tutaj powinieneś powiedzieć, sudoaby uruchomić nową zshpowłokę i powiedzieć, zshaby przeczytać ją ~/.zshrcprzed uruchomieniem tej funkcji:

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

Lub:

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

Lub, aby udostępnić bieżące funkcje zsh nowemu zshwywołanemu przez sudo:

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

Chociaż może pojawić się zbyt długi błąd listy argumentów, jeśli zdefiniowano wiele funkcji (na przykład podczas korzystania z systemu uzupełniania). Możesz więc chcieć ograniczyć go do findPortfunkcji (i każdej innej funkcji, na której polega, jeśli taka istnieje):

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

Możesz także:

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

Aby osadzić kod findPortfunkcji w funkcji anonimowej, do której należy przekazać argument 3306. Lub nawet:

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

(przekazany skrypt wbudowany -c jest treścią funkcji).

Możesz użyć funkcji pomocnika, takiej jak:

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

Nie używaj:

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

Ponieważ argumenty sdozostaną poddane kolejnemu poziomowi analizy składniowej powłoki. Porównać:

$ e() echo "$@"
$ sdo e 'tname;uname'
tname
Linux
$ zsudo e 'tname;uname'
tname;uname
Stéphane Chazelas
źródło
Potrzebuję rozwiązania tak krótkiego jak pisanie sudo. Byłem w stanie dostosować twoje anonimowe rozwiązanie funkcji do tego właśnie. Dodałem do mojej funkcji następującą funkcję ~/.zshrc, która służy do uruchamiania innych funkcji z podwyższonymi uprawnieniami:sdo() { sudo zsh -c "(){$functions[$1]} ${@:2}" }
Birchlabs,
1
@Birchlabs, patrz edycja
Stéphane Chazelas,
Dzięki; Zaktualizowałem swoją odpowiedź, aby użyć proponowanego nowszego skrótu.
Birchlabs,
Dodanie definicji funkcji do skryptu wykonanego za pomocą sudo jest sprytne. Ale niewystarczająco inteligentny, jeśli ta funkcja używa innej funkcji (automatycznie ładowanej lub nie).
Damien Flament,
3

Bardzo prostym rozwiązaniem było dla mnie wywołanie interaktywnej powłoki sudo -s, która wydaje się działać na mojej wersji Zsh (5.2) w pakiecie z macOS. To zapewnia mi funkcje z mojego ~/.zshrc.

Ze strony sudo, która tak naprawdę nie wskazuje na to zachowanie:

-s, --shell
Uruchom powłokę określoną przez zmienną środowiskową SHELL, jeśli jest ustawiona, lub powłokę określoną przez wpis bazy danych haseł użytkownika wywołującego. Jeśli podano polecenie, jest ono przekazywane do powłoki w celu wykonania za pomocą opcji -c powłoki. Jeśli nie podano żadnego polecenia, wykonywana jest powłoka interaktywna.

Nie jestem pewien, jaki jest twój przypadek użycia, ale podejrzewam, że szukasz interaktywnego rozwiązania.

jhat
źródło
To rzeczywiście działa. Chociaż nie chodziło mi o przepływ pracy, który miałem na myśli. Moim pragnieniem jest pozostawanie w monicie jako mój zwykły użytkownik i podniesienie tylko funkcji zdefiniowanej myFuncprzez użytkownika , poprzez wpisanie sudo myFunc- w ten sam sposób, w jaki podniosłbym dowolny proces (jak sudo rm -rf .). To rozwiązanie podnosi cały mój monit i wszystkie przyszłe funkcje, a także zmienia mojego użytkownika na wszystkie przyszłe funkcje - co jest nieco przesadzone.
Birchlabs
sudo -sKomenda uruchomi kolejną instancję swojej skorupy jako administrator. Jeśli wykonasz to polecenie interaktywnie, twoja nowa powłoka będzie interaktywna. Ale polecenie sudo -s findPort 3306uruchomi polecenie findPort 3306w powłoce jako administrator, a następnie zakończy działanie z kodem statusu tego polecenia.
Damien Flament,
2

Byłem w stanie wyprodukować stenogram wielokrotnego użytku dla jednego z rozwiązań opisanych w Stéphane Chazelas' odpowiedź . [Edycja: Stéphane powtórzył pierwotny skrót, który zaproponowałem; opisany tu kod jest nowszą wersją jego tworzenia]

Włóż to do swojego ~/.zshrc :

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

Teraz możesz użyć sdo jako „tylko sudodla funkcji zdefiniowanych przez użytkownika”.

Aby potwierdzić, że sdodziała: możesz wypróbować to na funkcji zdefiniowanej przez użytkownika, która drukuje twoją nazwę użytkownika.

 birch@server ~/ 🍔 test() whoami

 birch@server ~/ 🍔 test
birch

 birch@server ~/ 🍔 sdo test
root
Brzozy
źródło
0

Wydaje mi się, że to działa:

function sudo (){
  args="$@"
  /run/wrappers/bin/sudo -u "$USER" zsh -i -c "$args"
}
Chris Stryczyński
źródło