„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?


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

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.


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

0

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

function sudo (){
  args="$@"
  /run/wrappers/bin/sudo -u "$USER" zsh -i -c "$args"
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.