Как решить проблему "отказано в разрешении" при использовании sudo с перенаправлением в Bash?

При использовании sudo для разрешения редактирования файлов я регулярно получаю сообщение "отказано в разрешении".

Например, моя мышь дрожит и работает вяло, поэтому я хочу отключить опрос:

sudo echo "options drm_kms_helper poll=N">/etc/modprobe.d/local.conf

Мне будет предложено ввести пароль, а затем получить:

bash: /etc/modprobe.d/local.conf: Permission denied

Поэтому я попытался внести временные изменения, чтобы отключить опрос, используя:

sudo echo N> /sys/module/drm_kms_helper/parameters/poll

И снова система ответила:

bash: /sys/module/drm_kms_helper/parameters/poll: Permission denied

Есть какие-нибудь идеи?

Перенаправление выходных данных (через > operator) выполняется оболочкой, а не эхо. Вы должны войти в систему как root

sudo -i

Затем вы можете использовать перенаправление

echo N> /sys/module/drm_kms_helper/parameters/poll

В противном случае вы можете запустить строку bash с помощью sudo

sudo bash -c "echo N> /sys/module/drm_kms_helper/parameters/poll"

Перенаправление выходных данных выполняется оболочкой из которого была вызвана команда Итак, разбивая все на кусочки, вот что происходит*:

  • оболочка вызывает sudo echo "options drm_kms_helper poll=N", который выполняет sudo команда с echo "options drm_kms_helper poll=N" командная строка

  • sudo запрашивает пароль, открывает оболочку суперпользователя и вызывает echo "options drm_kms_helper poll=N", который работает echo команда, передающая его "options drm_kms_helper poll=N"

  • эхо, бегущее с root привилегии, выводит строку в ее стандартный вывод.

  • echo команда завершается, оболочка суперпользователя завершает работу, sudo завершает

  • оболочка, из которой была вызвана команда, собирает выходные данные и пытается перенаправить их на /etc/modprobe.d/local.conf, который доступен для записи только с помощью root. Он выдает ошибку "отказано в разрешении".

О том, как это исправить, см. в ответе @shantanu.


(*) - хотя приведенная выше последовательность помогает понять, почему команда завершается ошибкой, на самом деле все происходит несколько не по порядку: исходная оболочка замечает перенаправление и пытается открыть файл для записи перед вызовом sudo ... команда. При неудачном открытии файла оболочка даже не вызывает команду, которая должна была выполнить запись в файл (спасибо @PanosRontogiannis за указание на это).

Вот краткий тест:

$ touch ./onlyroot.txt$ sudo chown root:root ./onlyroot.txt$ sudo bash -c "whoami | tee who.txt" > onlyroot.txtbash: onlyroot.txt: Permission denied

В приведенном выше тесте whoami | tee who.txt собирался создать файл с именем who.txt содержащий слово "корень". Однако, когда перенаправление вывода завершается ошибкой в вызывающей оболочке, "who.txt " файл также отсутствует, поскольку команда не была вызвана.

Вы можете использовать tee команда, подобная этой:

sudo tee /sys/module/drm_kms_helper/parameters/poll <<<10

Или если это вывод команды:

echo 10 | sudo tee /sys/module/drm_kms_helper/parameters/poll

Если у вас возникла ситуация, когда вы хотели добавить, а не перезаписать целевой файл, то есть сделать tee вести себя как >> скорее, чем >-- вы бы использовали tee -a.

Подход, который я здесь не упоминал, заключается в том, чтобы просто выполнить всю командную строку в ее собственной оболочке. То sudo сама страница руководства дает пример такого подхода:

Чтобы составить список используемых каталогов в разделе /home. Обратите внимание, что при этом выполняются команды во вложенной оболочке, чтобы заставить работать перенаправление компакт-диска и файлов.

$ sudo sh -c "cd /home ; du -s * | sort -rn > USAGE"

Другой вариант - использовать временный файл. Это полезно в скрипте bash.

temp=$(mktemp)echo "Hello, world!" > $tempsudo cp $temp /etc/wherever

sudo dd of=

Чтобы добавить так, как вы хотите:

echo inbytes | sudo dd of=outfile oflag=append conv=notrunc

или воссоздать файл с нуля:

echo inbytes | sudo dd of=outfile

Преимущества:

Работает, потому что sudo пересылает stdin в команду.