为什么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
而不是为了它。
你需要:
- 引用redirect(所以它传递给
sudo)
- 并使用
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
,所以不推荐。
同时使用printf
和echo -e
,命令获得的参数string包含一个反斜杠,后跟一个字母N,然后input\n
,这取决于命令程序本身( printf
或echo
的代码)来转换换成换行符 在许多现代的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,并完全避免使用echo
或printf
:
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'
不会解释$arch
variables。
STE2源文件
$ source write_pacman.sh
STEP 3执行function
$ write_pacman