为什么sudo猫给予权限被拒绝,但sudo vim工作正常?

我正在尝试在arch的pacman.conf文件中自动添加存储库源代码,但是在我的shell脚本中使用了echo命令。 但是,它失败了,如下所示:

 sudo echo "[archlinuxfr]" >> /etc/pacman.conf sudo echo "Server = http://repo.archlinux.fr/\$arch" >> /etc/pacman.conf sudo echo " " >> /etc/pacman.conf -bash: /etc/pacman.conf: Permission denied 

如果我用vim手动修改/etc/pacman.conf,

 sudo vim /etc/pacman.conf 

并退出vim :wq ,一切正常,我的pacman.conf已被手动更新,没有“权限被拒绝”的投诉。

这是为什么? 我怎样才能让sudo echo工作? (顺便说一句,我尝试使用sudo cat但也失败了权限被拒绝以及)

问题是redirect正在被原始shell处理,而不是由sudo 。 壳是不能够阅读头脑,不知道这个特定>>是为了sudo而不是为了它。

你需要:

  1. 引用redirect(所以它传递给sudo)
  2. 使用sudo -s (以便sudo使用shell来处理引用的redirect。)

正如@geekosaur解释的那样,shell在运行命令之前执行redirect。 当你input这个:

 sudo foo >/some/file 

你当前的shell进程创build一个自己的副本,首先尝试打开/some/file进行写入,然后使该文件描述符成为其标准输出,然后才执行sudo

如果你被允许(sudoer configs通常排除运行shell),你可以做这样的事情:

 sudo bash -c 'foo >/some/file' 

但是我总体find一个好的解决方法就是使用| sudo tee | sudo tee而不是>| sudo tee -a | sudo tee -a而不是>> 。 如果redirect是我首先需要sudo的唯一原因,那么这是特别有用的; 毕竟,以root身份进行不必要的运行进程正是sudo被创build以避免的。 以root身份运行echo是愚蠢的。

 echo '[archlinuxfr]' | sudo tee -a /etc/pacman.conf >/dev/null echo 'Server = http://repo.archlinux.fr/$arch' | sudo tee -a /etc/pacman.conf >/dev/null echo ' ' | sudo tee -a /etc/pacman.conf >/dev/null 

我在末尾添加了> /dev/null ,因为tee将它的输出发送到指定的文件它自己的标准输出,而且我不需要在terminal上看到它。 ( tee命令的作用就像一个物理pipe道中的“T”连接器,这就是获取它的名字的地方)。然后我切换到单引号( '' )而不是双( "" ),这样一切都是字面的,我不必在$ in $arch前面加一个反斜杠。

所以,照顾使用sudo作为根文件写入文件。 现在对于在shell脚本中输出含有换行符的文本的方法进行了长时间的讨论。 🙂

首先,你可以将所有的echo分组在一起,所以你只需要redirect一次:

 (echo '[archlinuxfr] echo 'Server = http://repo.archlinux.fr/$arch' echo ' ') | sudo tee -a /etc/pacman.conf >/dev/null 

或者使用printf而不是echo ,所以你可以使用\n将新行直接embedded到string中:

 printf '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | sudo tee -a /etc/pacman.conf >/dev/null 

bash ,你可以用echo -e得到相同的结果:

 # BASH ONLY - NOT RECOMMENDED echo -e '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | sudo tee -a /etc/pacman.conf >/dev/null 

但是大多数shell只会输出-e ,所以不推荐。

同时使用printfecho -e ,命令获得的参数string包含一个反斜杠,后跟一个字母N,然后input\n ,这取决于命令程序本身( printfecho的代码)来转换换成换行符 在许多现代的shell中,你可以select使用ANSI引号$'' ,它会在命令程序看到string之前将\n这样的序列转换成文字换行符,这意味着这样的string可以和任何命令一起工作:

 echo $'[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | sudo tee -a /etc/pacman.conf >/dev/null 

但是,虽然比echo -e更便携,但ANSI引号仍然是非POSIX扩展名。

我这样做的首选方法是使用here-document,并完全避免使用echoprintf

 sudo tee -a /etc/pacman.conf >/dev/null <<'EOF' [archlinuxfr] Server = http://repo.archlinux.fr/$arch EOF 

http://www.innovationsts.com/blog/?p=2758

由于上面的说明不太清楚,我正在使用该博客文章中的说明。 有了这些例子,你就可以更容易地看到你需要做什么。

$ sudo cat /root/example.txt | gzip> /root/example.gz
-bash:/root/example.gz:权限被拒绝

请注意,这是导致错误的pipe道中的第二个命令(gzip命令)。 这就是我们用-c选项使用bash的技巧。

$ sudo bash -c'cat /root/example.txt | gzip> /root/example.gz'
$ sudo ls /root/example.gz
/root/example.gz

我们可以看到压缩文件创build成功的ls命令的输出。

第二种方法与第一种类似,我们将命令string传递给bash,但是我们通过sudo在pipe道中执行。

$ sudo rm /root/example.gz
$ echo“cat /root/example.txt | gzip> /root/example.gz”| sudo bash
$ sudo ls /root/example.gz
/root/example.gz

 sudo bash -c 'echo "[archlinuxfr]" >> /etc/pacman.conf' 

第1步在bash文件中创build一个函数

 ## write_pacman.sh write_pacman(){ sudo tee -a /etc/pacman.conf > /dev/null << 'EOF' [archlinuxfr] Server = http://repo.archlinux.fr/\$arch EOF } 

'EOF'不会解释$archvariables。

STE2源文件

 $ source write_pacman.sh 

STEP 3执行function

 $ write_pacman