How to solve "permission denied" when using sudo with redirection in Bash?
When using sudo to allow edits to files, I regularly get 'permission denied'.
For example, my mouse is jittery and sluggish, so I want to disable polling:
sudo echo "options drm_kms_helper poll=N">/etc/modprobe.d/local.conf
I'm prompted for a password, and then get:
bash: /etc/modprobe.d/local.conf: Permission denied
So I tried to do a temporary change to disable polling by using:
sudo echo N> /sys/module/drm_kms_helper/parameters/poll
Yet again the system responded with:
bash: /sys/module/drm_kms_helper/parameters/poll: Permission denied
Any ideas?
Output redirection (via the >
operator) is done by the shell, not by echo. You have to login as root
sudo -i
Then you can use redirection
echo N> /sys/module/drm_kms_helper/parameters/poll
Otherwise you can run bash string with sudo
sudo bash -c "echo N> /sys/module/drm_kms_helper/parameters/poll"
The output redirection is done by the shell from which the command has been invoked. So, breaking everything into bits, here what is happening*:
shell invokes
sudo echo "options drm_kms_helper poll=N"
, which executessudo
command withecho "options drm_kms_helper poll=N"
command linesudo asks for a password, opens superuser shell and invokes
echo "options drm_kms_helper poll=N"
, which runsecho
command passing it"options drm_kms_helper poll=N"
echo, running with
root
privileges, prints the string to its standard output.echo
command terminates, superuser shell exits,sudo
terminatesthe shell from which the command has been invoked collects the output and tries to redirect it to
/etc/modprobe.d/local.conf
, which is writeable only by root. It gets "permission denied" error.
For the ways to fix this see @shantanu answer.
(*) - while the above sequence helps to understand why the command fails, in reality things happen somewhat out-of-order: the original shell notices the redirection and tries to open the file for writing before invoking the sudo ...
command. When opening the file fails the shell doesn't even invoke the command which was supposed to write to the file (thanks to @PanosRontogiannis for pointing this out).
Here's a quick test:
$ touch ./onlyroot.txt
$ sudo chown root:root ./onlyroot.txt
$ sudo bash -c "whoami | tee who.txt" > onlyroot.txt
bash: onlyroot.txt: Permission denied
In the test above the whoami | tee who.txt
was going to create a file named who.txt
containing the word "root". However, when the output redirection fails in the calling shell, "who.txt" file is also missing because the command was not invoked.
You can use a tee
command like this:
sudo tee /sys/module/drm_kms_helper/parameters/poll <<<10
Or if its a command's output:
echo 10 | sudo tee /sys/module/drm_kms_helper/parameters/poll
If you had a situation where you wanted to append rather than overwrite the target file--that is, to make tee
behave like >>
rather than >
--you would use tee -a
.