sudo echo "something" >> /etc/privilegedFile不起作用。

715

这是一个相当简单的问题,至少看起来应该是,在Linux中关于sudo权限的问题。

有很多时候我只想将一些东西附加到/etc/hosts或类似的文件中,但最终无法做到,即使是用root也不允许使用>>>

有没有什么方法可以使这个工作正常运行而不必进入root的susudo su

15个回答

1092

使用tee --appendtee -a命令。

echo 'deb blah ... blah' | sudo tee -a /etc/apt/sources.list

确保避免在引号内部使用引号。

为了避免将数据打印回控制台,请将输出重定向到/dev/null。

echo 'deb blah ... blah' | sudo tee -a /etc/apt/sources.list > /dev/null

记得使用 (-a/--append) 标志! 只用 tee 命令会像 > 一样覆盖你的文件。而 tee -a 命令会像 >> 一样在文件末尾写入。


6
我绝对更喜欢这个。它非常简单易懂(并且教会了我关于茶的知识,这在其他情境中也很方便)。 - Joachim Sauer
6
我同意。似乎比开始一个新的sh更加整洁,特别是在可能需要处理环境等方面。 - Sam Brightman
43
重要提示:永远不要忘记 -a!想象一下,如果你执行 echo 'tmpfs /tmp tmpfs defaults 0 0' | sudo tee /etc/fstab 命令会发生什么。 - mic_e
22
在 macOS 系统下,应该使用 tee -a 而不是 tee --append - knite
32
对于那些不理解@mic_e说的话的人:没有加-a (--append) 标志该命令会覆盖整个文件,而不是将给定字符串追加到文件末尾。 - totymedli
1
记录一下,在Ubuntu Server 16.04上,你需要使用-a选项,--append会被忽略,正如@totymedli所示。 - James

359

问题在于shell进行输出重定向,而不是sudo或echo,因此这是以你的常规用户身份执行的。

尝试以下代码片段:

sudo sh -c "echo 'something' >> /etc/privilegedfile"

“sudo权限边界”是什么?这只是shell以明显的原因将重定向运算符解析为比命令更高的优先级。 - Vinko Vrsalovic
1
根据您的sh,echo可以在单引号内解释转义序列,例如\t。您可以使用printf %s 'something'代替。 - Lri
1
使用tee更受欢迎且更兼容于新的发行版。 - Eduardo B.
1
这是唯一一个可以作为SSH命令直接在远程节点上执行的命令。 - Duncan Lock
1
我同意这里其他帖子的观点。这个程序只使用了shell,因此不需要像tee这样的其他程序。是的,我知道tee已经安装好了,但是可能取决于你使用的微型发行版,比如裸骨的alpine。我也喜欢你提供了一个shell选项:例如 sudo /bin/bash -c "echo 'fs.inotify.max_user_watches = 524288' > /etc/sysctl.d/60-golang-inotify.conf" - akahunahi
很好,这样你也可以使用sudo重复上一个命令:sudo sh -c "!!" - rubo77

37

问题在于处理重定向的是你的 shell,它试图以 你的 权限而不是你在 sudo 下运行的进程的权限打开文件。

可以尝试类似这样的做法:

sudo sh -c "echo 'something' >> /etc/privilegedFile"

@GordonSun 这是因为 sudo(出于安全原因)不会将环境传递给子进程。您可以使用 sudo -E 来绕过此限制。 - arielf
1
@GordonSun 是的,它会生效,我不明白你为什么要重复这个说法!如果你使用双引号执行 sudo sh -c "echo 'something' >> $FILENAME",它 一定会 生效——变量替换是由外层 shell 而不是 sudo 后的 shell 完成的。 - Nadav Har'El
不支持多行输出的echo。 - mjs

23
sudo sh -c "echo 127.0.0.1 localhost >> /etc/hosts"

16

进行中

sudo sh -c "echo >> somefile"

应该可以正常工作。问题是">"和">>"由您的 shell 处理,而不是由 "sudoed" 命令处理,因此权限是您自己的,而不是您 "sudo" 到的用户的权限。


11

值得一提的是,如果你需要引用大段文本,也可以使用heredoc语法:

sudo bash -c "cat <<EOIPFW >> /etc/ipfw.conf
<?xml version=\"1.0\" encoding=\"UTF-8\"?>

<plist version=\"1.0\">
  <dict>
    <key>Label</key>
    <string>com.company.ipfw</string>
    <key>Program</key>
    <string>/sbin/ipfw</string>
    <key>ProgramArguments</key>
    <array>
      <string>/sbin/ipfw</string>
      <string>-q</string>
      <string>/etc/ipfw.conf</string>
    </array>
    <key>RunAtLoad</key>
    <true></true>
  </dict>
</plist>
EOIPFW"

2
这个很好用,只是嵌入的引号可能需要用 \ 转义。 - N Jones
非常正确,@NJones!我会编辑我的回答。(但是请注意,不这样做会去掉内部的 " 但不会导致命令失败。) - msanford

10
在bash中,您可以使用tee> /dev/null结合使用,以保持stdout干净。
 echo "# comment" |  sudo tee -a /etc/hosts > /dev/null

10

有些用户在使用多行时不知道解决方案。

sudo tee -a  /path/file/to/create_with_text > /dev/null <<EOT 
line 1
line 2
line 3
EOT

5

使用Yoo的答案,将这段内容放入你的~/.bashrc文件中:

sudoe() {
    [[ "$#" -ne 2 ]] && echo "Usage: sudoe <text> <file>" && return 1
    echo "$1" | sudo tee --append "$2" > /dev/null
}

现在你可以运行sudoe 'deb blah # blah' /etc/apt/sources.list
编辑: 更完整的版本允许您将输入管道传入或从文件重定向,并包括一个-a开关以关闭默认的追加模式:
sudoe() {
  if ([[ "$1" == "-a" ]] || [[ "$1" == "--no-append" ]]); then
    shift &>/dev/null || local failed=1
  else
    local append="--append"
  fi

  while [[ $failed -ne 1 ]]; do
    if [[ -t 0 ]]; then
      text="$1"; shift &>/dev/null || break
    else
      text="$(cat <&0)"
    fi

    [[ -z "$1" ]] && break
    echo "$text" | sudo tee $append "$1" >/dev/null; return $?
  done

  echo "Usage: $0 [-a|--no-append] [text] <file>"; return 1
}

3

您还可以使用来自 moreutils 包的 sponge,而无需重定向输出(即没有要隐藏的tee噪音):

echo 'Add this line' | sudo sponge -a privfile

-a 追加到文件。 - Akhil
@Akhil,如果你有问题,请留下有意义的评论。如果你有陈述或关注点,请留下有意义的评论。如果你发现错误或遗漏,请留下有意义的评论。你看到我的陈述中出现了一个模式吗? - Michael Goldshteyn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接