在Bash中使用带有重定向的sudo时如何解决“权限被拒绝”?

当使用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 

有任何想法吗?

输出重定向(通过>运算符)由shell完成,而不是由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" 

输出重定向由调用该命令的shell完成。 所以,把所有东西都打成碎片,这里发生了什么*:

  • shell调用sudo echo "options drm_kms_helper poll=N" ,它使用echo "options drm_kms_helper poll=N"命令行执行sudo命令

  • sudo要求输入密码,打开超级用户shell并调用echo "options drm_kms_helper poll=N" ,它运行echo命令传递它"options drm_kms_helper poll=N"

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

  • echo命令终止,超级用户shell退出, 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 whoami | tee who.txt将创建一个名为who.txt的文件, who.txt包含“root”一词。 但是,当调用shell中的输出重定向失败时,“who.txt”文件也会丢失,因为未调用该命令。

添加到Shantanu的答案:

…或者您可以使用这样的tee命令:

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

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

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

我在这里没有提到的方法是简单地在自己的shell中执行整个命令行。 sudo页本身就是这种方法的一个例子:

在/ home分区中创建目录的用法列表。 请注意,这会在子shell中运行命令以使cd和文件重定向工作。

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

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

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

sudo dd of=

要根据需要追加:

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

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

 echo inbytes | sudo dd of=outfile 

好处:

  • 因为没有/dev/null重定向,所以比tee更好
  • sh更好,因为没有明确的子shell(但是重定向的隐式子shell)
  • dd有许多强大的选项,例如status=progress来查看转移进度

因为sudo将stdin转发给命令而工作。