我正在尝试在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
并使用:wq
退出vim,一切正常,我的pacman.conf已经手动更新,没有“Permission denied”投诉。
为什么会这样?我如何让sudo echo
工作? (顺便说一句,我也尝试使用sudo cat
,但失败的权限也被拒绝了)
答案 0 :(得分:110)
正如@geekosaur解释的那样,shell在运行命令之前执行重定向。当你输入这个:
sudo foo >/some/file
您当前的shell进程会创建自己的副本,首先尝试打开/some/file
进行写入,然后将该文件描述符作为标准输出,然后才执行sudo
。
如果你被允许(sudoer configs经常阻止运行shell),你可以这样做:
sudo bash -c 'foo >/some/file'
但我发现一个好的解决方案通常是使用| sudo tee
代替>
和| sudo tee -a
而不是>>
。如果重定向是我首先需要sudo
的唯一原因,那么这尤其有用;毕竟,以root身份不必要地运行进程正是sudo
创建的要避免的。以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
将其输出发送到 指定文件和自己的标准输出,我不知道我需要在终端上看到它。 (tee
命令在物理管道中就像一个“T”连接器,它就是它的名字。)我切换到单引号('
... '
)而不是双打("
... "
),以便所有内容都是文字的,我不必在$
中的$arch
前放置反斜杠。
这样就可以使用sudo
以root身份写入文件。现在对在shell脚本中输出包含换行符的文本的方法进行冗长的讨论。 :)
首先,您可以在子shell中将所有echo
组合在一起,因此您只需要进行一次重定向:
(echo '[archlinuxfr]
echo 'Server = http://repo.archlinux.fr/$arch'
echo ' ') | sudo tee -a /etc/pacman.conf >/dev/null
或使用printf
代替echo
,因此您可以使用\n
将换行符直接嵌入到字符串中:
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
,命令作为参数字符串获取的内容包含一个文字反斜杠,后跟一个文字N,无论您键入\n
,它都取决于命令程序本身(printf
或echo
内的代码)将其转换为换行符。在许多现代shell中,您可以选择使用ANSI引号$'
... '
,它会在命令之前将\n
之类的序列转换为 literal 换行符程序永远看到字符串,这意味着这些字符串可以使用任何命令:
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
答案 1 :(得分:42)
问题是原始shell正在处理重定向,而不是sudo
。贝壳不能阅读思想,也不知道那个特定的>>
是针对sudo
而不是针对它的。{1}}。
你需要:
sudo)
sudo -s
(以便sudo
使用shell来处理引用的重定向。)答案 2 :(得分:17)
http://www.innovationsts.com/blog/?p=2758
由于上面的说明不明确,我使用的是博客文章中的说明。通过示例,您可以更轻松地查看需要执行的操作。
$ sudo cat /root/example.txt | gzip&gt; /root/example.gz
-bash:/root/example.gz:权限被拒绝
请注意,这是导致错误的管道中的第二个命令(gzip命令)。这就是我们使用带有-c选项的bash的技术。
$ sudo bash -c'cat /root/example.txt | gzip&gt; /root/example.gz“
$ sudo ls /root/example.gz
/root/example.gz
我们可以从ls命令的输出中看到压缩文件创建成功。
第二种方法类似于第一种方法,因为我们将命令字符串传递给bash,但我们是通过sudo在管道中进行的。
$ sudo rm /root/example.gz
$ echo“cat /root/example.txt | gzip&gt; /root/example.gz”| sudo bash
$ sudo ls /root/example.gz
/root/example.gz
答案 3 :(得分:5)
sudo bash -c 'echo "[archlinuxfr]" >> /etc/pacman.conf'
答案 4 :(得分:1)
第1步在bash文件中创建一个函数(write_pacman.sh
)
#!/bin/bash
function write_pacman {
tee -a /etc/pacman.conf > /dev/null << 'EOF'
[archlinuxfr]
Server = http://repo.archlinux.fr/\$arch
EOF
}
'EOF'
不会解释$arch
变量。
STE2 来源bash文件
$ source write_pacman.sh
第3步执行功能
$ write_pacman
答案 5 :(得分:0)
附加文件(sudo cat):
cat <origin-file> | sudo tee -a <target-file>
将回声追加到文件(sudo回声):
echo <origin> | sudo tee -a <target-file>
(EXTRA)忽略输出:
echo >origin> | sudo tee -a <target-file> >/dev/null