正如@geekosaur 解释的那样,shell 在运行命令之前会进行重定向。当您键入以下内容时:
sudo foo >/some/file
您当前的 shell 进程会创建一个自身的副本,该副本首先尝试打开/some/file
以进行写入,然后如果成功,它将将该文件描述符作为标准输出,并且只有成功时才会执行sudo
。这是第一步失败的。
如果您被允许(sudoer 配置通常会阻止运行 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”连接器,这就是它的名字。)我切换到单引号('
... '
)而不是双引号( "
... ),"
所以一切都是字面的,我不必在 in 前面加上$
反斜杠$arch
。(如果没有引号或反斜杠,$arch
将被 shell 参数的值替换,该值arch
可能不存在,在这种情况下,$arch
将被任何内容替换并消失。)
这样就可以使用sudo
. 现在对在 shell 脚本中输出包含换行符的文本的方法进行了冗长的题外话。:)
正如他们所说,为了 BLUF 它,我首选的解决方案是将此处的文档输入到上述sudo tee
命令中;那么根本不需要cat
or echo
or printf
or 任何其他命令。单引号已移至前哨引言<<'EOF'
,但它们在那里具有相同的效果:正文被视为文字文本,因此$arch
不用管:
sudo tee -a /etc/pacman.conf >/dev/null <<'EOF'
[archlinuxfr]
Server = http://repo.archlinux.fr/$arch
EOF
但是,虽然我会这样做,但还有其他选择。这里有几个:
您可以坚持echo
每行一个,但将它们全部组合在一个子shell中,因此您只需附加到文件一次:
(echo '[archlinuxfr]'
echo 'Server = http://repo.archlinux.fr/$arch'
echo ' ') | sudo tee -a /etc/pacman.conf >/dev/null
如果您添加-e
到echo
(并且您使用的是支持该非 POSIX 扩展的 shell),您可以使用以下命令将换行符直接嵌入到字符串中\n
:
# NON-POSIX - NOT RECOMMENDED
echo -e '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' |
sudo tee -a /etc/pacman.conf >/dev/null
但正如上面所说,这不是 POSIX 指定的行为。您的 shell 可能只是回显一个文字-e
,然后是一个带有一堆文字\n
s 的字符串。这样做的 POSIX 方法是使用printf
而不是echo
; 它会自动处理其参数echo -e
,但不会在末尾自动添加换行符,因此您也必须在\n
此处添加一个额外的:
printf '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n \n' |
sudo tee -a /etc/pacman.conf >/dev/null
对于这些解决方案中的任何一个,命令作为参数字符串得到的内容包含两个字符的序列\n
,并且由命令程序本身(内部的代码printf
or echo
)将其转换为换行符。在许多现代 shell 中,您可以选择使用 ANSI 引号$'
... ,这将在命令程序看到字符串之前'
将序列\n
转换为文字换行符。这意味着此类字符串可以与任何命令一起使用,包括普通的旧-e
-less echo
:
echo $'[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' |
sudo tee -a /etc/pacman.conf >/dev/null
但是,虽然比echo -e
ANSI 引号更便携,但它仍然是非 POSIX 扩展。
同样,虽然这些都是选项,但我更喜欢tee <<EOF
上面的直接解决方案。