我已经在我们的开发RedHat linux机器上获得了sudo访问权限,而且我似乎经常发现自己需要将输出重定向到我通常没有写访问权限的位置。
麻烦的是,这个人为的例子不起作用:
sudo ls -hal /root/ > /root/test.out
我刚收到回复:
-bash: /root/test.out: Permission denied
我该如何工作?
root
(在这种情况下,请继续阅读答案),但是通常,您只需要像其他人一样在其他位置创建文件。
我已经在我们的开发RedHat linux机器上获得了sudo访问权限,而且我似乎经常发现自己需要将输出重定向到我通常没有写访问权限的位置。
麻烦的是,这个人为的例子不起作用:
sudo ls -hal /root/ > /root/test.out
我刚收到回复:
-bash: /root/test.out: Permission denied
我该如何工作?
root
(在这种情况下,请继续阅读答案),但是通常,您只需要像其他人一样在其他位置创建文件。
Answers:
您的命令无效,因为重定向是由您的外壳执行的,该外壳没有写权限/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的答案。
使用启动shell,sudo -s
然后运行命令:
[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 -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 )
这里有人建议将steeing tee:
sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null
这也可以用于将任何命令重定向到您无权访问的目录。之所以起作用,是因为tee程序实际上是一个“回显文件”程序,并且重定向到/ dev / null就是要停止它并将其输出到屏幕上,以使其与上面的原始设计示例相同。
sudo
可以省略第一个(即对于命令本身)
我发现自己的一个窍门是
sudo ls -hal /root/ | sudo dd of=/root/test.out
sudo dd
比sudo tee /root/file > /dev/null
上面的例子好!
dd
是命令名称,of=/root/test.out
是dd
表明输出文件是什么的参数。
of
表示输出文件,dd
是Linux和OSX中都非常流行的工具(主要用于将映像写入磁盘)。当然,这是一个巧妙的技巧。
dd
可能和tee
这里一样有用。在这两种情况下,您都使用一个通用的,众所周知的命令,其目的虽然与最初的预期目的略有不同,但仍然是众所周知的且有据可查。虽然dd
擅长复制大量数据,但它不会吸收少量数据。这样做的好处是也不会将输出回显到标准输出。
sudo dd
彼此相邻的单词时,您都希望非常非常确定后面的参数正确(特别是考虑到其非标准语法)。他们不称其为“磁盘破坏者”……
问题是命令在下运行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"
澄清为什么最好使用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写入的文件,而root是您问题的出处。
这样做是个好主意,因为生成输出的命令不会以提升的特权执行。这似乎无关紧要,echo
但是当source命令是一个您不完全信任的脚本时,它至关重要。
请注意,您可以使用-a选项tee来将追加(如>>
)添加到目标文件,而不是覆盖它(如>
)。
我要处理此问题的方法是:
如果您需要写/替换文件:
echo "some text" | sudo tee /path/to/file
如果需要附加到文件:
echo "some text" | sudo tee -a /path/to/file
编写脚本怎么样?
文件名:myscript
#!/bin/sh
/bin/ls -lah /root > /root/test.out
# end script
然后使用sudo运行脚本:
sudo ./myscript
并不是要打败老马,但是这里使用的答案太多tee
,这意味着您必须重定向stdout
到,/dev/null
除非您想在屏幕上看到副本。
一个更简单的解决方案是cat
像这样使用:
sudo ls -hal /root/ | sudo bash -c "cat > /root/test.out"
请注意,如何将重定向放在引号中,以便由启动外壳程序sudo
而不是运行该外壳程序的外壳程序进行评估。
sudo bash -c "ls -hal /root > /root/test.out"
。使用tee避免需要外壳,而cat则不需要。
这是基于涉及的答案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/
设备的简单保护措施,这是此页评论之一中提到的一个问题。
sudo at now
at> echo test > /tmp/test.out
at> <EOT>
job 1 at Thu Sep 21 10:49:00 2017
sudo
反正at
是没有用的或必要的。sudo sh -c 'echo test >/tmp/test.out'
这样做的效率和优雅度更高(但仍然存在缺陷,即您可能正在运行root
不需要该特权的事物;通常应尽可能避免使用特权命令)。