131

I am trying to follow what I assume is best practices of using sudo instead of root account.

I am running a simple concat file operation such as:

sudo echo 'clock_hctosys="YES"' >> /etc/conf.d/hwclock

This fails as to the right of the ">>" it is running as the normal user. Adding extra sudos also fails (expected behaviour since piping to the sudo command and not to the file).

Example is just that but it has been verified and tested under the root account.

Ciro Santilli OurBigBook.com
  • 18,092
  • 4
  • 117
  • 102
DarkSheep
  • 1,886
  • 3
  • 15
  • 18

6 Answers6

151

You can invoke a new shell as root:

sudo sh -c 'echo clock_hctosys=\"YES\" >> /etc/conf.d/hwclock'

You could also just elevate a process to write to the file:

sudo tee -a /etc/conf.d/hwclock > /dev/null << EOF
clock_hctosys="YES"
EOF
Chris Down
  • 125,559
  • 25
  • 270
  • 266
  • 14
    In general the second option is more safe because only the tee commands runs as root, not the main command which could be complex and prone to misbehaviour. (not the case of echo) – pabouk - Ukraine stay strong Feb 14 '15 at 11:27
  • 2
    echo 'clock_hctosys="YES"' | sudo tee -a /etc/conf.d/hwclock >/dev/null also does the job for something more complicated than echo (when we need the command output) without invoking this command under root – avtomaton Dec 02 '20 at 10:09
27

Another option, equally safe, is to use sudo's -i switch to log in as root:

$ sudo -i
# echo clock_hctosys=\"YES\" >> /etc/conf.d/hwclock'

This still follows best practice rules since the root account is not actually enabled as such but lets you do things as root safely. From man sudo:

The -i (simulate initial login) option runs the shell
    specified by the password database entry of the target user
    as a login shell.  This means that login-specific resource
    files such as .profile or .login will be read by the shell.
    If a command is specified, it is passed to the shell for
    execution via the shell's -c option.  If no command is
    specified, an interactive shell is executed. 
terdon
  • 242,166
26

sudo dd of=

To append as you want:

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

or to recreate the file from scratch:

echo inbytes | sudo dd of=path/to/outfile

Advantages:

  • nicer than tee since no /dev/null redirection
  • nicer than sh since no subshell
  • dd has many powerful options, e.g. status=progress to see transfer progress

Works because sudo forwards stdin to the command.

Ciro Santilli OurBigBook.com
  • 18,092
  • 4
  • 117
  • 102
18

If you express your command without single quotes, you can put it inside single quotes and execute that via an intermediate shell.

To execute this as root:

echo 'clock_hctosys="YES"' >> /etc/conf.d/hwclock

Write the command a different way that doesn't use ':

echo clock_hctosys=\"YES\" >> /etc/conf.d/hwclock

Then invoke sudo sh -c …:

sudo sh -c 'echo clock_hctosys=\"YES\" >> /etc/conf.d/hwclock'

Alternatively, to write output to a file that only root can write to, call sudo tee. Pass the -a option to tee to append to the destination file, otherwise the file is truncated.

echo 'clock_hctosys="YES"' | sudo tee -a /etc/conf.d/hwclock >/dev/null

For more complex file modifications, you can call sudo sed, sudo ed, sudo perl, …

Alternatively, use a decent editor and make it call sudo. In Emacs, open /sudo:/etc/conf.d/hwclock. In Vim, call :w !sudo tee % to write to the opened file as root, or use the sudo.vim plugin. Or go from the sudo end and call sudoedit /etc/conf.d/hwclock.

Or you can give in to the dark side and run a shell as root.

$ sudo -i
# echo 'clock_hctosys="YES"' >> /etc/conf.d/hwclock
Kusalananda
  • 333,661
12

The command fails due to the permissions on the file redirected to. The redirection happens even before the sudo command is invoked.

You will have to make sure that it's root that actually openes the file for writing.

The simplest way of doing that:

echo 'clock_hctosys="YES"' | sudo tee -a /etc/conf.d/hwclock >/dev/null

The echo may be run as you ordinary user as it just produces a text string. The tee utility will have to run as root though, and tee -a will append data. We redirect the output to /dev/null because tee, by default, will duplicate its input data to its standard output in addition to writing to the indicated files.

With bash or any shell that understands "here-strings":

sudo tee -a /etc/conf.d/hwclock >/dev/null <<<'clock_hctosys="YES"'

This is identical in effect to the above. Only the way we produce the string is changed.


Another, slightly roundabout way of doing it:

sudo sh -c 'echo clock_hctosys=\"YES\" >>/etc/conf.d/hwclock'

Here, the redirection happens within a sh -c child shell running as root.

Or, giving the line to append as an argument to the sh -c shell running as root:

sudo sh -c 'printf "%s\n" "$1" >>/etc/conf.d/hwclock' sh 'clock_hctosys="YES"'

... which could be generalized into something that adds all arguments as lines to the file:

set -- 'line 1' 'line 2' 'line 3'
sudo sh -c 'printf "%s\n" "$@" >>/etc/conf.d/hwclock' sh "$@"
Kusalananda
  • 333,661
2

Surprised how rarely this tool is brought up considering how useful it is:

sponge from the package moreutils. It's available on basically every distro under this same name, and can handle several situations that shell redirection does poorly.

The original intended purpose is to allow reading from and then writing back into the same file (which shell redirect fails at because the redirection is processed first). However it is also excellent for this purpose:

echo "hello world" | sudo sponge /path/to/privileged/file

Easy as this. And if you need to append rather than overwrite (>>), there's the -a flag.

See manual.

cyqsimon
  • 785
  • 7
  • 22