我在我们开发的RedHat Linux盒子上被授予sudo访问权限,而我似乎经常需要将输出重定向到通常没有写入权限的位置。
麻烦的是,这个人为的例子不起作用:
sudo ls -hal /root/ > /root/test.out
我刚刚收到响应:
-bash: /root/test.out: Permission denied
我该如何让这个工作?
我在我们开发的RedHat Linux盒子上被授予sudo访问权限,而我似乎经常需要将输出重定向到通常没有写入权限的位置。
麻烦的是,这个人为的例子不起作用:
sudo ls -hal /root/ > /root/test.out
我刚刚收到响应:
-bash: /root/test.out: Permission denied
我该如何让这个工作?
你的命令无法正常执行,因为重定向是由你的shell执行的,而该shell没有写入 /root/test.out
的权限。输出的重定向不是通过sudo执行的。
有多种解决方案:
使用-c
选项以sudo身份运行shell,并将命令交给它:
sudo sh -c 'ls -hal /root/ > /root/test.out'
创建一个包含你的命令的脚本,并使用sudo运行该脚本:
#!/bin/sh
ls -hal /root/ > /root/test.out
运行sudo ls.sh
命令。如果不想创建临时文件,请参考Steve Bennett的回答。
使用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
为了防止tee在屏幕上输出,必须重定向到/dev/null
。如果要进行追加输出而不是覆盖原有内容,则使用tee -a
或tee --append
(最后一个选项仅适用于GNU coreutils)。感谢Jd、Adam J. Forster和Johnathan提供第二、三和四种解决方案。perl -e 'print "STDIN\n"; print STDERR "STDERR\n"; ' > >( tee stdout.log ) 2> >( tee stderr.log >&2 )
。 - curious_prismtee
以外,我发现另一个好的解决方案是在 heredoc 语句中使用 sudo bash <<EOF echo -e "$(whoami)\n$(ls -l)\n$(pstree -sp $$)" > a whoami pstree -sp $$ EOF
,此时 shell 扩展可以正常工作,并允许在非 root 环境下执行命令,最终将所有结果重定向为 sudo 到特权文件,这里文件 a
的所有者是 root。 - dinesh saini这里有人建议使用sudo tee:
sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null
这也可以用于重定向任何命令到一个你没有访问权限的目录。它起作用是因为 tee 程序实际上是一个“输出到文件”的程序,而对 /dev/null 的重定向是为了防止它也输出到屏幕上,以使它与上面的原始例子保持相同。
sudo
(即用于命令本身)可能会被省略。 - Hagen von Eitzenmoreutils
包中的sponge
工具。它的功能与tee
完全相同,唯一的区别是它不会输出到stdout
,因此您可以不必将输出重定向到/dev/null
。所以您只需输入ls -hal /root/ | sudo sponge /root/test.out
即可。 - cyqsimon我自己想出来的一个技巧是
sudo ls -hal /root/ | sudo dd of=/root/test.out
sudo tee /root/file > /dev/null
的例子不如使用 sudo dd
更好! - kristianlmdd
是命令名称,of=/root/test.out
是参数,告诉 dd
输出文件的位置。 - rhleeof
意味着输出文件,而 dd
是在Linux和OSX中广泛使用的工具(主要用于将映像写入磁盘)。这确实是一个不错的技巧。 - blockloopsudo dd
这些单词时,一定要非常、非常确保其后面的参数是正确的(特别是考虑到其非标准语法)。毫不夸张地说,它的名字叫做“磁盘毁灭者”... - ali_m问题在于命令是在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"
安排一个具备所需权限(例如sudo)的管道/子Shell
# 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';
又是主题的另一种变化:
sudo bash <<EOF
ls -hal /root/ > /root/test.out
EOF
或者当然:
echo 'ls -hal /root/ > /root/test.out' | sudo bash
这样做的一个(微小的)优点是您不需要记忆任何 sudo
或 sh
/bash
的参数。
稍微解释一下为什么使用tee选项更好
假设您具有执行创建输出命令的适当权限,如果将命令输出导向到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写入的文件中,这是您提出问题的原因。
以这种方式执行是一个好主意,因为生成该输出的命令未使用提升的权限来执行。对于使用您不完全信任的脚本作为源命令时,这似乎并不重要,但这是至关重要的。
请注意,您可以使用 -a 选项将 tee 用于追加(类似于 >>
)到目标文件,而不是覆盖它(类似于 >
)。
请执行以下命令:
sudo sh -c "echo foo > ~root/out"
我处理这个问题的方式是:
如果您需要编写/替换文件:
echo "some text" | sudo tee /path/to/file
如果您需要向文件追加内容:echo "some text" | sudo tee -a /path/to/file
不是想要重复说一遍,但这里有太多使用tee
的答案,这意味着你必须将stdout
重定向到/dev/null
,除非你想在屏幕上看到一份副本。
一个更简单的解决方案是只使用cat
:
sudo ls -hal /root/ | sudo bash -c "cat > /root/test.out"
注意重定向符号放在引号中,这样它将被由sudo
启动的一个shell解释而非当前shell解释。
sudo bash -c "ls -hal /root > /root/test.out"
好多少。使用tee命令可以避免需要shell,而cat却做不到。 - Nick Russo写一个脚本怎么样?
文件名:myscript
#!/bin/sh
/bin/ls -lah /root > /root/test.out
# end script
sudo ./myscript
sudo
权限的文件的权限。如果您拥有sudo
权限,请使用sudo bash
(或您喜欢的shell)在该shell中执行操作。 - Noel Yap