正如@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命令中;那么根本不需要cator echoor printfor 任何其他命令。单引号已移至前哨引言<<'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,然后是一个带有一堆文字\ns 的字符串。这样做的 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,并且由命令程序本身(内部的代码printfor 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 -eANSI 引号更便携,但它仍然是非 POSIX 扩展。
同样,虽然这些都是选项,但我更喜欢tee <<EOF上面的直接解决方案。