我在我们的一个开发 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 执行的,它没有写入权限/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 的回答。
启动一个 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
or tee --append
(最后一个特定于GNU coreutils)。
感谢Jd、Adam J. Forster和Johnathan提供的第二个、第三个和第四个解决方案。
这里有人刚刚建议 sudoing tee:
sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null
这也可用于将任何命令重定向到您无权访问的目录。它之所以有效,是因为 tee 程序实际上是一个“回显到文件”程序,并且重定向到 /dev/null 是为了阻止它也输出到屏幕,以保持它与上面最初的人为示例相同。
我自己发现的一个技巧是
sudo ls -hal /root/ | sudo dd of=/root/test.out
问题是命令在 下运行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)
# 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';
澄清一下为什么 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 写入的文件,这是您问题的根源。
这样做是个好主意,因为生成输出的命令不是以提升的权限执行的。在这里似乎无关紧要,echo
但是当源命令是您不完全信任的脚本时,这一点至关重要。
请注意,您可以使用 -a 选项 tee 将追加(like >>
)附加到目标文件而不是覆盖它(like >
)。
主题的另一个变体:
sudo bash <<EOF
ls -hal /root/ > /root/test.out
EOF
或者当然:
echo 'ls -hal /root/ > /root/test.out' | sudo bash
他们有一个(微小的)优势,你不需要记住任何参数sudo
or sh
/bash
让 sudo 运行一个 shell,如下所示:
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"
请注意重定向是如何放在引号内的,以便它由一个 shell 启动sudo
而不是运行它的一个 shell 来评估它。
写个剧本怎么样?
文件名:myscript
#!/bin/sh
/bin/ls -lah /root > /root/test.out
# end script
然后使用 sudo 运行脚本:
sudo ./myscript
我会这样做:
sudo su -c 'ls -hal /root/ > /root/test.out'
每当我必须做这样的事情时,我就会成为 root:
# sudo -s
# ls -hal /root/ > /root/test.out
# exit
这可能不是最好的方法,但它确实有效。
这是基于涉及的答案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 访问权限?那么就没有办法做你想做的事了。(除非你会以某种方式破解它)
如果不是这样,那么也许您可以编写 bash 脚本:
cat > myscript.sh
#!/bin/sh
ls -hal /root/ > /root/test.out
按ctrl+ d:
chmod a+x myscript.sh
sudo myscript.sh
希望它有所帮助。
sudo at now
at> echo test > /tmp/test.out
at> <EOT>
job 1 at Thu Sep 21 10:49:00 2017