在Bash中将sudo与重定向一起使用时,如何解决“权限被拒绝”?


137

当使用sudo允许对文件进行编辑时,我经常会得到“权限被拒绝”。

例如,我的鼠标抖动而缓慢,因此我想禁用轮询:

sudo echo "options drm_kms_helper poll=N">/etc/modprobe.d/local.conf

系统提示我输入密码,然后获取:

bash: /etc/modprobe.d/local.conf: Permission denied

因此,我尝试使用以下方法进行临时更改以禁用轮询:

sudo echo N> /sys/module/drm_kms_helper/parameters/poll

系统再次回应:

bash: /sys/module/drm_kms_helper/parameters/poll: Permission denied

有任何想法吗?

Answers:


156

输出重定向(通过>操作符)是由外壳程序完成的,而不是由echo完成的。您必须以root身份登录

sudo -i

然后您可以使用重定向

echo N> /sys/module/drm_kms_helper/parameters/poll

否则,您可以使用sudo运行bash字符串

sudo bash -c "echo N> /sys/module/drm_kms_helper/parameters/poll"

1
您不能使用sudo运行echo吗?我得到的结果如何:saji@laptop:~$ sudo echo "Hi" [sudo] password for saji: Hi
saji89

您可以写在文件上,回显“ something”> somewhre。它正在使用管道。这就是问题所在。
shantanu 2012年

4
好的,如果是这样,请更新您的答案以反映仅在这种情况下运行回显才是问题。
saji89

您不能简单地将内置的shell echo作为sudo 运行,除非您执行类似的操作sudo bash -c 'echo …';但是,POSIX系统通常会提供外部echo命令,例如/bin/echo在OS X上,而sudo可以在没有rigamarole的情况下执行。因此,echo您通常运行的echo命令和使用sudo运行的命令可能是两个不同但相似的命令。
kojiro 2012年

如果是这样,为什么对这个问题的回答暗示了回声?askubuntu.com/questions/840431/…–
Harsha

75

输出重定向由调用命令的外壳完成。因此,将所有内容分解为零,这是正在发生的事情*:

  • shell invokes sudo echo "options drm_kms_helper poll=N",它sudo通过echo "options drm_kms_helper poll=N"命令行执行命令

  • sudo要求输入密码,打开超级用户外壳程序并调用echo "options drm_kms_helper poll=N",然后运行echo传递该命令的命令"options drm_kms_helper poll=N"

  • echo,以root特权运行,将字符串输出到其标准输出。

  • echo命令终止,超级用户外壳退出,sudo终止

  • 从中调用命令的shell收集输出,并尝试将其重定向到/etc/modprobe.d/local.conf,该目录只能由root写入。它得到“权限被拒绝”错误。

有关解决此问题的方法,请参见@shantanu答案。


(*)-尽管上述顺序有助于理解命令失败的原因,但实际上事情会有些混乱:原始shell会注意到重定向,并在调用sudo ...命令之前尝试打开文件进行写入。当打开文件失败时,shell甚至不会调用应该写入文件的命令(感谢@PanosRontogiannis指出了这一点)。

这是一个快速测试:

$ touch ./onlyroot.txt
$ sudo chown root:root ./onlyroot.txt
$ sudo bash -c "whoami | tee who.txt" > onlyroot.txt
bash: onlyroot.txt: Permission denied

在上面的测试中,whoami | tee who.txt打算创建一个who.txt包含单词“ root”的文件。但是,当调用外壳程序中的输出重定向失败时,也会丢失“ who.txt”文件,因为未调用命令。


外壳更有可能自己“分叉”,并在尝试执行sudo之前尝试打开/etc/modprobe.d/local.conf,这意味着您描述的前4个步骤实际上从未发生,因为无法打开文件。
Panos Rontogiannis '16

1
@PanosRontogiannis:谢谢,我已经更新了答案
Sergey

60

添加到Shantanu的答案:

...或者您可以使用如下tee命令:

sudo tee /sys/module/drm_kms_helper/parameters/poll <<<10

或者如果它是命令的输出:

echo 10 | sudo tee /sys/module/drm_kms_helper/parameters/poll

3
以root身份+1登录对于手动工作来说是一个坏主意,对于脚本化任务来说则是一个非常不好的主意。
l0b0

2
另外,sudo tee /sys/module/drm_kms_helper/parameters/poll > /dev/null如果您不希望它也可以打印stdout
Fabian Tamp 2015年

16

我这里没有提到的一种方法是简单地在自己的shell中执行整个命令行。该sudo联机帮助页给出了这种方法的一个例子:

列出/ home分区中目录的用途。请注意,这将在子外壳程序中运行命令以使cd和文件重定向正常工作。

$ sudo sh -c "cd /home ; du -s * | sort -rn > USAGE"

哇谢谢。一个简单的解决方案
弹性

4

另一种选择是使用临时文件。这在bash脚本中很有用。

temp=$(mktemp)
echo "Hello, world!" > $temp
sudo cp $temp /etc/wherever

3

sudo dd of=

根据需要添加:

echo inbytes | sudo dd of=outfile oflag=append conv=notrunc

或从头开始重新创建文件:

echo inbytes | sudo dd of=outfile

好处:

  • tee没有/dev/null重定向更好
  • sh没有显式子外壳要好(但对于重定向是隐式的)
  • dd有很多强大的选项,例如status=progress查看传输进度

有效,因为sudo将stdin转发到命令。


1
很好 我们想到的dd是如何覆盖曾经很棒的文件系统,但也没有意识到它也适用于平凡的任务-如果将根目录下的其他命令用于错误的文件/设备上,也会造成极大的危害。就像sudo teesudo dd当然也可以在这里使用字符串,例如sudo dd of=outfile <<<'hello world'。[感谢编辑。NB用sh -c 'cmd'sh是一个子进程,这是一个外壳,但没有真正除非意义上的子shell 所有外部命令开始为一体。
利雅卡根
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.