201

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?

Jack
  • 3,899

7 Answers7

248

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"
shantanu
  • 8,599
  • 1
    You can't run echo with sudo? the what about the result I got: saji@laptop:~$ sudo echo "Hi" [sudo] password for saji: Hi – saji89 Dec 19 '12 at 04:41
  • 1
    you can write on file, echo "something" > somewhre. It's using pipe.. That is the problem. – shantanu Dec 19 '12 at 04:55
  • 4
    Ok, if that's the case, then please update your answer to reflect that running echo is a problem in that case only. – saji89 Dec 19 '12 at 04:59
  • 1
    You can't simply run the shell builtin echo as sudo, unless you do something like sudo bash -c 'echo …'; however, POSIX systems usually supply an external echo command such as /bin/echo on OS X, which sudo can execute without rigamarole. Thus, the echo command you usually run and the echo command you run with sudo are probably two different, but similar commands. – kojiro Dec 19 '12 at 13:48
  • If that is the case, why did the answers to this question suggest echo? http://askubuntu.com/questions/840431/high-cpu-usage-for-kidle-inject-x-in-ubuntu-16-10 – Harsha Feb 26 '17 at 13:12
88

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 executes sudo command with echo "options drm_kms_helper poll=N" command line

  • sudo asks for a password, opens superuser shell and invokes echo "options drm_kms_helper poll=N", which runs echo 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 terminates

  • the 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.

Sergey
  • 43,665
  • 1
    More likely the shell 'forks' itself and tries to open /etc/modprobe.d/local.conf before trying to 'exec' sudo which means that the first 4 steps your describe never actually happen because the file cannot be opened. – Panos Rontogiannis May 30 '16 at 09:32
  • 1
    @PanosRontogiannis: thanks, I've updated the answer – Sergey Jun 06 '16 at 20:35
  • I upvoted but IMHO the (*) has to be replaced with the first part of the answer and then the first part can be used as a simplification in the (*) part for those who might need it. – aderchox Sep 08 '20 at 07:11
73

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.

Eliah Kagan
  • 117,780
Untitled
  • 1,448
  • 4
    +1 logging in as root is a bad idea for manual work, and a really bad idea for scripted tasks. – l0b0 Dec 19 '12 at 16:41
  • 2
    Also, sudo tee /sys/module/drm_kms_helper/parameters/poll > /dev/null if you don't want it printing to stdout as well. – Fabian Tamp Oct 27 '15 at 07:46
19

An approach I haven't seen mentioned here is to simply execute the entire commandline in its own shell. The sudo manpage itself gives an example of this approach:

To make a usage listing of the directories in the /home partition. Note that this runs the commands in a sub-shell to make the cd and file redirection work.

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

Another option is to use a temporary file. This is useful in a bash script.

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

sudo dd of=

To append as you want:

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

or to recreate the file from scratch:

echo inbytes | sudo dd of=outfile

Advantages:

Works because sudo forwards stdin to the command.

  • 1
    This is good. We think of dd as how we overwrite our once-great filesystems, and don't realize it's for mundane tasks too--and that other commands as root also cause great harm if used on on the wrong files/devices. Like sudo tee, sudo dd will of course also work with here strings, e.g., sudo dd of=outfile <<<'hello world'. [Thanks for editing. NB with sh -c 'cmd', sh is a subprocess that's a shell, but not really a subshell except in the sense all external commands begin as one.] – Eliah Kagan Oct 24 '17 at 16:00
1

Create a one-line script from your command, then execute the script as sudo. For example:

  1. Use an editor to create a file; for example:

    nano my_script.sh
    
  2. In the editor, insert your shebang, and the command:

    #!/bin/bash  
    echo "options drm_kms_helper poll=N" > /etc/modprobe.d/local.conf  
    
  3. Save the file & exit the editor; e.g. ~/my_script.sh

  4. Make the file executable:

    chmod 755 ~/my_script.sh
    
  5. Run the script under sudo:

    sudo ./my_script.sh
    
muru
  • 197,895
  • 55
  • 485
  • 740
Seamus
  • 636