如何使用sudo将输出重定向到我无权写入的位置?

时间:2008-09-17 11:44:40

标签: linux permissions sudo io-redirection permission-denied

我已经在我们的一个开发RedHat linux盒子上获得了sudo访问权限,我似乎发现自己经常需要将输出重定向到我通常没有写入权限的位置。

麻烦的是,这个人为的例子不起作用:

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

我刚收到回复:

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

我怎样才能让它发挥作用?

15 个答案:

答案 0 :(得分:1106)

您的命令不起作用,因为您的shell执行重定向,但没有写入/root/test.out的权限。输出的重定向不是由sudo执行。

有多种解决方案:

  • 使用sudo运行shell并使用-c选项向其发出命令:

    sudo sh -c 'ls -hal /root/ > /root/test.out'
    
  • 使用您的命令创建脚本并使用sudo运行该脚本:

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

    运行sudo ls.sh。如果您不想创建临时文件,请参阅Steve Bennett的answer

  • 使用sudo -s启动shell,然后运行命令:

    [nobody@so]$ sudo -s
    [root@so]# ls -hal /root/ > /root/test.out
    [root@so]# ^D
    [nobody@so]$
    
  • 使用sudo tee(如果在使用-c选项时必须逃避很多):

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

    需要重定向到/dev/null才能阻止tee输出到屏幕。要追加而不是覆盖输出文件 (>>),使用tee -atee --append(最后一个特定于GNU coreutils)。

感谢JdAdam J. ForsterJohnathan获取第二,第三和第四个解决方案。

答案 1 :(得分:92)

这里有人刚刚建议sudoing tee:

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

这也可以用于将任何命令重定向到您无权访问的目录。它的工作原理是因为tee程序实际上是一个“回显到文件”程序,重定向到/ dev / null是为了阻止它也输出到屏幕以使其与上面原始设计的例子保持一致。

答案 2 :(得分:74)

我自己想出的一个技巧

sudo ls -hal /root/ | sudo dd of=/root/test.out

答案 3 :(得分:41)

问题是命令sudo下运行,但重定向会在您的用户下运行。这是由shell完成的,你可以做的很少。

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

绕过这个的常用方法是:

  • 将命令包装在您在sudo下调用的脚本中。

    如果命令和/或日志文件发生变化,您可以进行更改 脚本将这些作为参数。例如:

    sudo log_script command /log/file.txt
    
  • 调用shell并将命令行作为参数传递给-c

    这对于一个复合命令特别有用。 例如:

    sudo bash -c "{ command1 arg; command2 arg; } > /log/file.txt"
    

答案 4 :(得分:20)

主题的又一个变体:

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

当然还是:

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

他们具有(微小)优势,您无需记住sudosh / bash

的任何参数

答案 5 :(得分:18)

澄清为什么选择T恤选项

假设您具有执行创建输出的命令的适当权限,如果您将命令的输出传递给tee,您只需要使用sudo提升tee的权限并直接将tee写入(​​或追加)到该文件中问题

在问题中给出的例子意味着:

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

有几个更实际的例子:

# 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

在每个示例中,您将获取非特权命令的输出并写入通常只能由root写入的文件,这是您问题的来源。

这样做是个好主意,因为生成输出的命令不会使用提升的权限执行。这与echo似乎并不重要,但是当源命令是一个你不完全信任的脚本时,它是至关重要的。

请注意,您可以使用-a选项将tee附加到目标文件(如>>),而不是覆盖它(如>)。

答案 6 :(得分:16)

让sudo运行一个shell,如下所示:

sudo sh -c "echo foo > ~root/out"

答案 7 :(得分:9)

我对这个问题的看法是:

如果您需要写/替换文件:

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

如果您需要附加到文件:

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

答案 8 :(得分:5)

编写脚本怎么样?

文件名:myscript

#!/bin/sh

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

# end script

然后使用sudo运行脚本:

sudo ./myscript

答案 9 :(得分:4)

我会这样做:

sudo su -c 'ls -hal /root/ > /root/test.out'

答案 10 :(得分:3)

每当我必须做这样的事情时,我才会成为根:

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

这可能不是最好的方式,但它确实有效。

答案 11 :(得分:3)

不要故意击败死马,但这里使用tee的答案太多了,这意味着你必须将stdout重定向到/dev/null,除非你想看到屏幕上的副本。一个更简单的解决方案就是像这样使用cat

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

注意重定向如何放在引号内,以便由sudo启动的shell而不是运行它的shell进行评估。

答案 12 :(得分:2)

这是基于tee的答案。为了方便起见,我编写了一个小脚本(我称之为suwrite)并将其/usr/local/bin/置于+x权限中:

#! /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

如代码中的 USAGE 所示,您所要做的就是将输出通过管道输出到此脚本,然后输入所需的超级用户可访问文件名,它会自动提示您输入密码。需要(因为它包括sudo)。

echo test | suwrite /root/test.txt

请注意,由于这是tee的简单包装,它还会接受tee的-a选项进行追加,并且还支持同时写入多个文件。

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

它还有一些简单的保护措施,可以防止写入/dev/设备,这是本页评论中提到的一个问题。

答案 13 :(得分:1)

也许您只能获得某些程序/路径的sudo访问权限?然后没有办法做你想要的。 (除非你以某种方式破解它)

如果不是这样,那么也许你可以编写bash脚本:

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

ctrl + d

chmod a+x myscript.sh
sudo myscript.sh

希望有所帮助。

答案 14 :(得分:0)

sudo at now  
at> echo test > /tmp/test.out  
at> <EOT>  
job 1 at Thu Sep 21 10:49:00 2017