Как решить "отказано в разрешении" при использовании 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

Есть идеи?

7 ответов

Решение

Перенаправление вывода (через > оператор) выполняется оболочкой, а не эхом. Вы должны войти в систему как 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.txt
bash: 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

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

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

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

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

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

sudo dd of=

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

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

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

echo inbytes | sudo dd of=outfile

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

  • лучше чем tee так как нет /dev/null перенаправление
  • лучше чем sh поскольку нет явной подоболочки (но неявной для перенаправления)
  • dd имеет много мощных опций, например status=progress чтобы увидеть прогресс передачи

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

Создайте однострочный скрипт из своей команды, затем выполните скрипт как . Например:

  1. Используйте редактор для создания файла; Например:

            nano my_script.sh
    
  2. В редакторе вставьте свой шебанг и команду:

            #!/bin/bash  
    echo "options drm_kms_helper poll=N" > /etc/modprobe.d/local.conf  
    
  3. Сохраните файл и выйдите из редактора; например ~/my_script.sh

  4. Сделайте исполняемый файл:

            chmod 755 ~/my_script.sh
    
  5. Запустите скрипт под sudo:

            sudo ./my_script.sh
    
Другие вопросы по тегам