相关文章推荐
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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

Ask Question

This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers . If you believe the question would be on-topic on another Stack Exchange site , you can leave a comment to explain where the question may be able to be answered.

Closed 2 years ago .

The community reviewed whether to reopen this question 8 months ago and left it closed:

Original close reason(s) were not resolved

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?

@DombiSzabolcs You are suggesting that I create the file as sudo first, then give myself permission? Good idea. – Jonathan Jul 10, 2016 at 15:36 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. – tripleee Feb 14, 2019 at 9:32 After struggling with these answers I finally choose to redirect to a temp file and sudo move it to destination. – TingQian LI Aug 1, 2019 at 15:03

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.

    There's a great answer that tells you how to redirect STDERR and STDOUT separately here: stackoverflow.com/questions/692000/… ... basically perl -e 'print "STDIN\n"; print STDERR "STDERR\n"; ' > >( tee stdout.log ) 2> >( tee stderr.log >&2 ) – curious_prism Jun 13, 2013 at 11:40 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). – Urhixidur Feb 14, 2014 at 21:28 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. – thomasrutter Jul 7, 2015 at 1:36 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. – dinesh saini Apr 26, 2022 at 9:47

    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.

    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 omitted – Hagen von Eitzen Aug 26, 2016 at 8:38 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. – cyqsimon Mar 9 at 4:10 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. – rhlee Jul 24, 2013 at 18:48 @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. – blockloop Apr 14, 2014 at 19:24 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. – thomasrutter Jul 7, 2015 at 1:39 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... – ali_m Jan 5, 2016 at 21:44

    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';
    

    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 >).

    Sorry js3, but this has already been suggested (back in 2008) and is sitting at the second highest answer: stackoverflow.com/a/82553/6910 – Jonathan Nov 6, 2013 at 10:24 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. – jg3 Nov 7, 2013 at 18:23 It's not "substantially different" but it clarifies the distinctive usage between replacing and appending to the file. – jamadagni Feb 4, 2019 at 10:54

    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.

    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. – Nick Russo Dec 9, 2016 at 4:49 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) – pabouk - Ukraine stay strong Jul 28, 2013 at 11:34

    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
    for arg in "$@" ; do
        if [ ${arg#/dev/} != ${arg} ] ; then
            echo "Found dangerous argument ‘$arg’. Will exit."
            exit 2
    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.

    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). – tripleee Jun 29, 2018 at 6:11

    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.

  •  
    推荐文章