提问人:Jonathan 提问时间:9/17/2008 最后编辑:Jonathan 更新时间:12/6/2021 访问量:330545
如何使用 sudo 将输出重定向到我无权写入的位置?[关闭]
How do I use sudo to redirect output to a location I don't have permission to write to? [closed]
问:
这个问题似乎与特定的编程问题、软件算法或程序员主要使用的软件工具无关。如果您认为该问题在另一个 Stack Exchange 站点上是主题,您可以发表评论以解释在哪里可以回答该问题。
2年前关闭。
去年,社群审查了是否要重新讨论这个问题,并关闭了这个问题:
原始关闭原因未解决
我被授予了我们开发的 RedHat linux 机器之一的 sudo 访问权限,我似乎发现自己经常需要将输出重定向到我通常没有写入权限的位置。
问题是,这个人为的例子不起作用:
sudo ls -hal /root/ > /root/test.out
我刚刚收到回复:
-bash: /root/test.out: Permission denied
我怎样才能让它工作?
答:
写剧本怎么样?
文件名: myscript
#!/bin/sh
/bin/ls -lah /root > /root/test.out
# end script
然后使用 sudo 运行脚本:
sudo ./myscript
让 sudo 运行一个 shell,如下所示:
sudo sh -c "echo foo > ~root/out"
您的命令不起作用,因为重定向是由您的 shell 执行的,而 shell 没有写入 的权限。sudo 不执行输出的重定向。/root/test.out
有多种解决方案:
使用 sudo 运行一个 shell,并使用以下选项向其发出命令:
-c
sudo sh -c 'ls -hal /root/ > /root/test.out'
使用命令创建一个脚本,并使用 sudo 运行该脚本:
#!/bin/sh ls -hal /root/ > /root/test.out
跑。如果您不想创建临时文件,请参阅 Steve Bennett 的回答。
sudo ls.sh
启动一个 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
需要重定向到以阻止 T 恤输出到屏幕。追加而不是覆盖输出文件 ()、use 或 (最后一个是特定于 GNU coreutils 的)。
/dev/null
>>
tee -a
tee --append
感谢 Jd、Adam J. Forster 和 Johnathan 提供第二、第三和第四种解决方案。
评论
perl -e 'print "STDIN\n"; print STDERR "STDERR\n"; ' > >( tee stdout.log ) 2> >( tee stderr.log >&2 )
tee
sudo bash <<EOF echo -e "$(whoami)\n$(ls -l)\n$(pstree -sp $$)" > a whoami pstree -sp $$ EOF
a
每当我必须做这样的事情时,我就会成为root:
# sudo -s
# ls -hal /root/ > /root/test.out
# exit
这可能不是最好的方法,但它有效。
也许您只获得了对某些程序/路径的 sudo 访问权限?那么就没有办法做你想做的事了。(除非你会以某种方式破解它)
如果不是这种情况,那么也许你可以编写 bash 脚本:
cat > myscript.sh
#!/bin/sh
ls -hal /root/ > /root/test.out
按 + :ctrld
chmod a+x myscript.sh
sudo myscript.sh
希望对你有所帮助。
这里有人刚刚建议 sudoing tee:
sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null
这也可用于将任何命令重定向到您无权访问的目录。它之所以有效,是因为 tee 程序实际上是一个“文件回显”程序,重定向到 /dev/null 是为了阻止它也输出到屏幕,以保持它与上面的原始人为示例相同。
评论
sudo
sponge
moreutils
tee
stdout
/dev/null
ls -hal /root/ | sudo sponge /root/test.out
问题是命令在 下运行,但重定向在您的用户下运行。这是由 shell 完成的,您对此无能为力。sudo
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';
我自己想出的一个技巧是
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
dd
可能和这里一样有用。在这两种情况下,您都使用一个通用的、众所周知的命令来实现一个目的,尽管该命令与其原始预期目的略有不同,但仍然是众所周知的且有据可查的。虽然擅长复制大量数据,但它不会因少量数据而吝啬。它的好处是不会将输出回显到标准输出。tee
dd
sudo dd
我会这样做:
sudo su -c 'ls -hal /root/ > /root/test.out'
评论
su
$ sudo su -c 'pstree -sp $$ >/dev/fd/1'
init(1)───gnome-terminal(6880)───bash(6945)───sudo(401)───su(402)───bash(410)───pstree(411)
主题的另一个变体:
sudo bash <<EOF
ls -hal /root/ > /root/test.out
EOF
或者当然:
echo 'ls -hal /root/ > /root/test.out' | sudo bash
它们有一个(微小的)优势,即您不需要记住任何参数或sudo
sh
/bash
澄清一下为什么 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 选项将 append (like ) 附加到目标文件,而不是覆盖它 (like )。>>
>
评论
这是基于涉及 的答案。为了让事情变得更容易,我写了一个小脚本(我称之为 ),并在获得许可的情况下将其放入: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/
我解决这个问题的方式是:
如果需要写入/替换文件:
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 而不是运行它的 shell 进行评估。sudo
评论
sudo bash -c "ls -hal /root > /root/test.out"
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
评论
root