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?
The way we can redirect the output is by closing the current file descriptor and then reopening it, pointing to the new output. We'll do this using the open and dup2 functions. There are two default outputs in Unix systems, stdout and stderr. stdout is associated with file descriptor 1 and stderr to 2.
sudo is a command that give you root privilege. But sh is an interpreter. When you use sudo command , you running the command as root privilege. But when you use sudo sh command , you running the sh command as root.
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.
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.
A trick I figured out myself was
sudo ls -hal /root/ | sudo dd of=/root/test.out
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';
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With