«Команда не найдена» при выполнении функции sudo из ~ / .zshrc


10

У меня есть функция в моем ~/.zshrc:

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

Обычный вызов есть findPort 3306.

Я хочу запустить его с повышенными привилегиями. Но я получаю "команда не найдена".

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

Я предполагаю, что причина в том, что пользователь root либо работает как неинтерактивная оболочка (таким образом, не ссылается на .zshrc), либо ссылается на другую .zshrc .

Я видел похожие вопросы относительно alias, но не вопрос относительно пользовательских функций. Ответы на эту проблему касаются aliasдобавления псевдонима ~/.zshrc:

alias sudo='nocorrect sudo '

Или возможно:

alias sudo='sudo '

Я испробовал оба эти решения, и проблема все еще существует (да, я перезапустил оболочку).

Я также попытался запустить, sudo chshчтобы убедиться, что моя корневая оболочка работает zsh. Ни одно из этих решений не устраняет проблему «команда не найдена».

Есть ли способ запустить мои пользовательские функции под sudo?


См. Также: unix.stackexchange.com/questions/181414/… (без пометки, поскольку у zsh есть свои хитрости)
muru

Ответы:


13

sudoвыполняет команду непосредственно, а не через оболочку, и даже если он побежал оболочку для запуска этой команды, это будет новая оболочка вызов, а не один , который читает ваши ~/.zshrc(даже если он начал интерактивную оболочку, она, вероятно , читала root~/.zshrc, не ваше, если вы не настроили sudoне сбрасывать $HOMEпеременную).

Здесь вам нужно указать sudoзапустить новую zshоболочку и сказать, что вы zshдолжны прочитать ее ~/.zshrcперед запуском этой функции:

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

Или:

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

Или поделиться своими текущими функциями zsh с новыми, zshвызванными sudo:

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

Хотя вы можете получить слишком длинный список ошибок, если у вас определено много функций (например, при использовании системы завершения). Таким образом, вы можете захотеть ограничить его findPortфункцией (и любой другой функцией, на которую он опирается, если есть):

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

Вы также можете сделать:

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

Чтобы встроить код findPortфункции в анонимную функцию, которой вы передаете аргумент 3306. Или даже:

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

(передаваемый встроенный скрипт -c является телом функции).

Вы можете использовать вспомогательную функцию, например:

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

Не используйте:

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

В качестве аргументов sdoбудет проходить другой уровень разбора оболочки. Для сравнения:

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

Мне нужно решение, такое же короткое, как печатать sudo. Я смог адаптировать ваше решение анонимной функции, чтобы сделать именно это. Я добавил следующую функцию к моей ~/.zshrc, которая является функцией для запуска других функций с повышенными привилегиями:sdo() { sudo zsh -c "(){$functions[$1]} ${@:2}" }
Birchlabs

1
@Birchlabs, см. Редактирование
Стефан Шазелас

Спасибо; Я обновил свой ответ, чтобы использовать предложенный вами более новый ярлык.
Birchlabs

Добавление определения функции в сценарий, выполняемый с помощью sudo, является разумным. Но не достаточно умен, если эта функция использует другую функцию (автозагрузку или нет).
Дэмиен Фламент

3

Для меня очень простым решением было вызвать интерактивную оболочку с помощью sudo -s, которая, кажется, работает на моей версии zsh, связанной с macOS (5.2). Это предоставляет мне функции от моего ~/.zshrc.

Из man-страницы sudo, которая на самом деле не намекает на это поведение:

-s, --shell
Запустить оболочку, указанную в переменной среды SHELL, если она установлена, или оболочку, указанную в записи базы данных паролей вызывающего пользователя. Если указана команда, она передается в оболочку для выполнения через параметр оболочки -c. Если команда не указана, выполняется интерактивная оболочка.

Я не уверен, каков ваш вариант использования, но я подозреваю, что вы ищете интерактивное решение.


Это действительно работает. Хотя это не совсем рабочий процесс, который я имел в виду. Я хочу оставаться в приглашении, как мой обычный пользователь, и повышать только мою пользовательскую функцию myFunc, печатая sudo myFunc- так же, как я бы повышал любой процесс (например sudo rm -rf .). Это решение поднимает всю мою подсказку и все будущие функции, а также меняет моего пользователя на все будущие функции - что немного излишне.
Birchlabs

Команда sudo -sзапустит другой экземпляр вашей оболочки как суперпользователь. Если вы выполните эту команду в интерактивном режиме, ваша новая оболочка будет интерактивной. Но команда sudo -s findPort 3306запустит команду findPort 3306в вашей оболочке как суперпользователь, а затем выйдет с кодом состояния этой команды.
Дэмиен Фламент

2

Мне удалось создать сокращенное обозначение многократного использования для одного из решений, описанных в ответе Стефана Шазеласа . [Редактировать: Стефан перебрал исходный ярлык, который я предложил; код, описанный здесь, является более новой версией его создания]

Поместите это в свой ~/.zshrc:

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

Теперь вы можете использовать sdoкак «только sudoдля пользовательских функций».

Чтобы убедиться, что это sdoработает: вы можете попробовать его в пользовательской функции, которая печатает ваше имя пользователя.

 birch@server ~/ 🍔 test() whoami

 birch@server ~/ 🍔 test
birch

 birch@server ~/ 🍔 sdo test
root

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.