How do I use sudo to redirect output to a location I don't have permission to write to? [closed]
Asked Answered
S

15

1122

I've been given sudo access on one of our development RedHat linux boxes, and I seem to find myself quite often needing to redirect output to a location I don't normally have write access to.

The trouble is, this contrived example doesn't work:

sudo ls -hal /root/ > /root/test.out

I just receive the response:

-bash: /root/test.out: Permission denied

How can I get this to work?

Skirt answered 17/9, 2008 at 11:44 Comment(6)
use chmod u+w filenameBleeding
@DombiSzabolcs You are suggesting that I create the file as sudo first, then give myself permission? Good idea.Skirt
In many situations you end up here because you asked "why do I get Permission denied?" Sometimes the answer is that you do need to create a file as root (in which case proceed to read the answers) but very often, you simply need to create the file somewhere else, as yourself.Jitterbug
After struggling with these answers I finally choose to redirect to a temp file and sudo move it to destination.Septarium
See also #85382Apothem
NO! It is NOT generally a good idea to open up permissions to a file needing sudo permissions for security reasons. If you have sudo permissions, sudo bash (or your preferred shell) then perform the operations in that shell.Organist
A
1553

Your command does not work because the redirection is performed by your shell which does not have the permission to write to /root/test.out. The redirection of the output is not performed by sudo.

There are multiple solutions:

  • Run a shell with sudo and give the command to it by using the -c option:

    sudo sh -c 'ls -hal /root/ > /root/test.out'
    
  • Create a script with your commands and run that script with sudo:

    #!/bin/sh
    ls -hal /root/ > /root/test.out
    

    Run sudo ls.sh. See Steve Bennett's answer if you don't want to create a temporary file.

  • Launch a shell with sudo -s then run your commands:

    [nobody@so]$ sudo -s
    [root@so]# ls -hal /root/ > /root/test.out
    [root@so]# ^D
    [nobody@so]$
    
  • Use sudo tee (if you have to escape a lot when using the -c option):

    sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null
    

    The redirect to /dev/null is needed to stop tee from outputting to the screen. To append instead of overwriting the output file (>>), use tee -a or tee --append (the last one is specific to GNU coreutils).

Thanks go to Jd, Adam J. Forster and Johnathan for the second, third and fourth solutions.

Avestan answered 17/9, 2008 at 11:48 Comment(4)
There's a great answer that tells you how to redirect STDERR and STDOUT separately here: #692500 ... basically perl -e 'print "STDIN\n"; print STDERR "STDERR\n"; ' > >( tee stdout.log ) 2> >( tee stderr.log >&2 )Aria
You'll want to do 'sudo -E ...' in order to use variables in the shelled out command (when using this in a script, for instance).Caressive
Redirecting tee output to /dev/null is probably not necessary in a lot of cases where echoing the output to screen is harmless. For example, when dealing just with output of regular commands or contents of small text files.Dome
for reference: apart from tee other soultion i found good is sudo bash <<EOF echo -e "$(whoami)\n$(ls -l)\n$(pstree -sp $$)" > a whoami pstree -sp $$ EOF in heredoc statement shell expansion works so allowing command to be executed in not root environment and finally allowing all result redirected as sudo to priviledged file, here owener of file a is root.Radiography
S
142

Someone here has just suggested sudoing tee:

sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null

This could also be used to redirect any command, to a directory that you do not have access to. It works because the tee program is effectively an "echo to a file" program, and the redirect to /dev/null is to stop it also outputting to the screen to keep it the same as the original contrived example above.

Skirt answered 17/9, 2008 at 12:26 Comment(2)
In many cases, namely if the normal user has prmissions to perform the command and "only" cannot write to the desired output file, the first sudo (i.e., for the command itself) might be omittedSailmaker
There is also sponge from moreutils package. Works identically to tee except it doesn't output to stdout so you can forgo the redirect to /dev/null. So it would simply be ls -hal /root/ | sudo sponge /root/test.out.Allround
D
103

A trick I figured out myself was

sudo ls -hal /root/ | sudo dd of=/root/test.out
Dreher answered 21/11, 2011 at 14:24 Comment(11)
sudo dd is better than the sudo tee /root/file > /dev/null examples above!Hematite
nah, having to learn another weird, obscure command with weird, obscure syntax (of=..., really!) is not 'better'.Nw
dd is not a weird obscure command. It is used whenever you need to copy large amounts of data with buffering between two block devices. The syntax is actually pretty simple, dd is the command name, of=/root/test.out is the argument which tells dd what the Output Files is.Dreher
@steve Everything is 'obscure' until you learn what it is. of means output file and dd is a very popular tool used in both Linux and OSX (mostly for writing images to disks). This is a neat trick for sure.Octant
dd is probably equally useful as tee here. In both cases you're using a common, well-known command for a purpose that, while slightly different to its original intended purpose, is still well-known and well-documented. While dd is good at copying huge amounts of data, it doesn't suck with small amounts. It has the benefit here of not echoing the output to standard output as well.Dome
Whenever you type words sudo dd next to one another, you want to make very, very sure that the arguments that follow are correct (especially considering its non-standard syntax). They don't call it "disk destroyer" for nothing...Stenography
@Stenography sudo dd is dangerous (I like the "data destroyer" name) but sudo tee and sudo cat are equally capable of overwriting drives. It should really be sudo that's the red flag, but it's used so often... I really watch out for /dev/sd... or anything in /dev/ that's not null or zeroCawley
And dd had more features than tee, e.g. status=progress is awesome for flashing images.Lxx
Neat! Unfortunately, the append version is a bit too much verbose: ... | sudo dd of=out oflag=append conv=notruncOneal
Well actually this is not the same at all. dd by default works with blocks of 512 bytes and it can be dreaded slow. But tee tried to send data as fast as possible.Slowly
A(nother) difference (apart from the /dev/null thing) between using tee and dd is that tee can be used to output to multiple files.Leolaleoline
H
67

The problem is that the command gets run under sudo, but the redirection gets run under your user. This is done by the shell and there is very little you can do about it.

sudo command > /some/file.log
`-----v-----'`-------v-------'
   command       redirection

The usual ways of bypassing this are:

  • Wrap the commands in a script which you call under sudo.

    If the commands and/or log file changes, you can make the script take these as arguments. For example:

    sudo log_script command /log/file.txt
    
  • Call a shell and pass the command line as a parameter with -c

    This is especially useful for one off compound commands. For example:

    sudo bash -c "{ command1 arg; command2 arg; } > /log/file.txt"
    
  • Arrange a pipe/subshell with required rights (i.e. sudo)

    # Read and append to a file
    cat ./'file1.txt' | sudo tee -a '/log/file.txt' > '/dev/null';
    
    # Store both stdout and stderr streams in a file
    { command1 arg; command2 arg; } |& sudo tee -a '/log/file.txt' > '/dev/null';
    
Husbandry answered 23/9, 2008 at 10:10 Comment(0)
N
31

Yet another variation on the theme:

sudo bash <<EOF
ls -hal /root/ > /root/test.out
EOF

Or of course:

echo 'ls -hal /root/ > /root/test.out' | sudo bash

They have the (tiny) advantage that you don't need to remember any arguments to sudo or sh/bash

Nw answered 13/5, 2013 at 3:53 Comment(0)
E
28

Clarifying a bit on why the tee option is preferable

Assuming you have appropriate permission to execute the command that creates the output, if you pipe the output of your command to tee, you only need to elevate tee's privledges with sudo and direct tee to write (or append) to the file in question.

in the example given in the question that would mean:

ls -hal /root/ | sudo tee /root/test.out

for a couple more practical examples:

# kill off one source of annoying advertisements
echo 127.0.0.1 ad.doubleclick.net | sudo tee -a /etc/hosts

# configure eth4 to come up on boot, set IP and netmask (centos 6.4)
echo -e "ONBOOT=\"YES\"\nIPADDR=10.42.84.168\nPREFIX=24" | sudo tee -a /etc/sysconfig/network-scripts/ifcfg-eth4

In each of these examples you are taking the output of a non-privileged command and writing to a file that is usually only writable by root, which is the origin of your question.

It is a good idea to do it this way because the command that generates the output is not executed with elevated privileges. It doesn't seem to matter here with echo but when the source command is a script that you don't completely trust, it is crucial.

Note you can use the -a option to tee to append append (like >>) to the target file rather than overwrite it (like >).

Erde answered 2/11, 2013 at 1:51 Comment(2)
Sorry js3, but this has already been suggested (back in 2008) and is sitting at the second highest answer: https://mcmap.net/q/45641/-how-do-i-use-sudo-to-redirect-output-to-a-location-i-don-39-t-have-permission-to-write-to-closedSkirt
You're right, Jonathan, I'll update my answer to expand on the reasons why this is a preferable option. Thanks for the helpful feedback.Erde
P
26

Make sudo run a shell, like this:

sudo sh -c "echo foo > ~root/out"
Provenience answered 17/9, 2008 at 11:48 Comment(0)
B
18

The way I would go about this issue is:

If you need to write/replace the file:

echo "some text" | sudo tee /path/to/file

If you need to append to the file:

echo "some text" | sudo tee -a /path/to/file
Bookish answered 24/6, 2016 at 19:48 Comment(3)
How is this substantially different to answers above?Skirt
It's not "substantially different" but it clarifies the distinctive usage between replacing and appending to the file.Leolaleoline
This is the answer I copied to my cheat sheet.Barogram
S
14

Don't mean to beat a dead horse, but there are too many answers here that use tee, which means you have to redirect stdout to /dev/null unless you want to see a copy on the screen.

A simpler solution is to just use cat like this:

sudo ls -hal /root/ | sudo bash -c "cat > /root/test.out"

Notice how the redirection is put inside quotes so that it is evaluated by a shell started by sudo instead of the one running it.

Searle answered 28/7, 2016 at 9:27 Comment(1)
I think it doesn't get much love because it's not much better than sudo bash -c "ls -hal /root > /root/test.out". Using tee avoids needing a shell, while cat does not.Seedcase
C
6

How about writing a script?

Filename: myscript

#!/bin/sh

/bin/ls -lah /root > /root/test.out

# end script

Then use sudo to run the script:

sudo ./myscript
Cache answered 17/9, 2008 at 11:48 Comment(0)
I
5

Whenever I have to do something like this I just become root:

# sudo -s
# ls -hal /root/ > /root/test.out
# exit

It's probably not the best way, but it works.

Interoffice answered 17/9, 2008 at 11:49 Comment(0)
R
5

I would do it this way:

sudo su -c 'ls -hal /root/ > /root/test.out'
Remission answered 21/4, 2013 at 12:33 Comment(2)
That actually seems a bit cleaner, as you don't need to explicitly specify the shell.Nw
One small drawback is that it runs one additional process (su): $ sudo su -c 'pstree -sp $$ >/dev/fd/1' init(1)───gnome-terminal(6880)───bash(6945)───sudo(401)───su(402)───bash(410)───pstree(411)Decentralization
L
3

This is based on the answer involving tee. To make things easier I wrote a small script (I call it suwrite) and put it in /usr/local/bin/ with +x permission:

#! /bin/sh
if [ $# = 0 ] ; then
    echo "USAGE: <command writing to stdout> | suwrite [-a] <output file 1> ..." >&2
    exit 1
fi
for arg in "$@" ; do
    if [ ${arg#/dev/} != ${arg} ] ; then
        echo "Found dangerous argument ‘$arg’. Will exit."
        exit 2
    fi
done
sudo tee "$@" > /dev/null

As shown in the USAGE in the code, all you have to do is to pipe the output to this script followed by the desired superuser-accessible filename and it will automatically prompt you for your password if needed (since it includes sudo).

echo test | suwrite /root/test.txt

Note that since this is a simple wrapper for tee, it will also accept tee's -a option to append, and also supports writing to multiple files at the same time.

echo test2 | suwrite -a /root/test.txt
echo test-multi | suwrite /root/test-a.txt /root/test-b.txt

It also has some simplistic protection against writing to /dev/ devices which was a concern mentioned in one of the comments on this page.

Leolaleoline answered 27/11, 2013 at 4:55 Comment(0)
F
2
sudo at now  
at> echo test > /tmp/test.out  
at> <EOT>  
job 1 at Thu Sep 21 10:49:00 2017  
Fly answered 21/9, 2017 at 10:55 Comment(1)
If you have sudo anyway, at isn't useful or necessary. sudo sh -c 'echo test >/tmp/test.out' does the same much more efficiently and elegantly (but still suffers from the flaw that you are probably running things as root which don't need that privilege; you should generally avoid privileged commands when you can).Jitterbug
A
1

Maybe you been given sudo access to only some programs/paths? Then there is no way to do what you want. (unless you will hack it somehow)

If it is not the case then maybe you can write bash script:

cat > myscript.sh
#!/bin/sh
ls -hal /root/ > /root/test.out 

Press ctrl + d :

chmod a+x myscript.sh
sudo myscript.sh

Hope it help.

Arvizu answered 17/9, 2008 at 12:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.