"Команда не знайдена", коли функція sudo'ing від ~ / .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(навіть якщо він почав інтерактивну оболонку, вона, ймовірно , читала rootS » ~/.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 "() {$ функцій [$ 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, див. Редагування
Stéphane Chazelas

Дякую; Я оновив свою відповідь, щоб використати новіший ярлик, який ви запропонували.
Birchlabs

Додавання визначення функції до сценарію, виконаного через sudo, є розумним. Але недостатньо розумний, якщо ця функція використовує іншу функцію (автоматично завантажена чи ні).
Дамієн Фламент

3

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

З сайту mando sudo, яке насправді не натякає на таку поведінку:

-s, --shell
Запустіть оболонку, вказану змінною середовища SHELL, якщо вона встановлена, або оболонку, задану вводом бази даних пароля користувача, що викликає. Якщо вказана команда, вона передається в оболонку для виконання через опцію -c оболонки. Якщо команда не вказана, виконується інтерактивна оболонка.

Я не впевнений, у чому полягає ваша ситуація, але я підозрюю, що ви шукаєте інтерактивне рішення.


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

sudo -sКоманда запустить ще один екземпляр вашої оболонки в якості суперкористувача. Якщо ви виконаєте цю команду інтерактивно, ваша нова оболонка буде інтерактивною. Але команда sudo -s findPort 3306запустить команду findPort 3306у вашій оболонці як суперпользователь, а потім вийде з кодом статусу цієї команди.
Дамієн Фламент

2

Я був в змозі зробити багаторазові стенографії для одного з рішень , описаних в Stéphane Chazelas ' відповіді . [Редагувати: Стефан повторив оригінальний ярлик, який я запропонував; описаний тут код - це новіша версія його виготовлення]

Вставте це у своє ~/.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.