【问题标题】:How do I use sudo to redirect output to a location I don't have permission to write to? [closed]如何使用 sudo 将输出重定向到我无权写入的位置? [关闭]
【发布时间】:2021-08-15 17:20:05
【问题描述】:

我在我们的一个开发 RedHat linux 机器上获得了 sudo 访问权限,我似乎发现自己经常需要将输出重定向到我通常没有写入权限的位置。

问题是,这个人为的例子不起作用:

sudo ls -hal /root/ > /root/test.out

我刚刚收到回复:

-bash: /root/test.out: Permission denied

我怎样才能让它工作?

【问题讨论】:

  • 使用 chmod u+w 文件名
  • @DombiSzabolcs 您是在建议我先将文件创建为 sudo,然后再授予自己权限?好主意。
  • 在许多情况下,您最终会出现在这里,因为您问“为什么我会被拒绝权限?”有时答案是您确实需要创建一个文件为root(在这种情况下继续阅读答案),但通常您只需要像您自己一样在其他地方创建文件。
  • 在为这些答案苦苦挣扎之后,我最终选择重定向到一个临时文件并 sudo 将其移动到目的地。
  • 鉴于大量的赞成和回答,我觉得这篇文章应该被继承并重新打开,即使它不是严格按照现代定义的主题。它仍然是一个非常有用的参考问答。

标签: linux bash permissions sudo io-redirection


【解决方案1】:

写个脚本怎么样?

文件名:我的脚本

#!/bin/sh

/bin/ls -lah /root > /root/test.out

# end script

然后使用 sudo 运行脚本:

sudo ./myscript

【讨论】:

    【解决方案2】:

    让 sudo 运行一个 shell,像这样:

    sudo sh -c "echo foo > ~root/out"
    

    【讨论】:

      【解决方案3】:

      您的命令不起作用,因为重定向是由您的 shell 执行的,它没有写入 /root/test.out 的权限。输出的重定向不是由sudo执行的。

      有多种解决方案:

      • 使用 sudo 运行 shell 并使用 -c 选项向它发出命令:

        sudo sh -c 'ls -hal /root/ > /root/test.out'
        
      • 使用您的命令创建一个脚本并使用 sudo 运行该脚本:

        #!/bin/sh
        ls -hal /root/ > /root/test.out
        

        运行sudo ls.sh。如果您不想创建临时文件,请参阅 Steve Bennett 的 answer

      • 使用sudo -s 启动一个shell,然后运行你的命令:

        [nobody@so]$ sudo -s
        [root@so]# ls -hal /root/ > /root/test.out
        [root@so]# ^D
        [nobody@so]$
        
      • 使用sudo tee(如果您在使用-c 选项时必须经常转义):

        sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null
        

        需要重定向到/dev/null 以阻止tee 输出到屏幕。 追加而不是覆盖输出文件 (>>),使用tee -atee --append(最后一个是GNU coreutils特有的)。

      感谢JdAdam J. ForsterJohnathan 提供第二、第三和第四种解决方案。

      【讨论】:

      • 这里有一个很好的答案告诉你如何分别重定向 STDERR 和 STDOUT:stackoverflow.com/questions/692000/… ... 基本上是perl -e 'print "STDIN\n"; print STDERR "STDERR\n"; ' > >( tee stdout.log ) 2> >( tee stderr.log >&2 )
      • 您需要执行 'sudo -E ...' 以在脱壳命令中使用变量(例如,在脚本中使用它时)。
      • 在将输出回显到屏幕无害的许多情况下,可能不需要将 tee 输出重定向到 /dev/null。例如,仅处理常规命令的输出或小文本文件的内容时。
      【解决方案4】:

      每当我必须做这样的事情时,我都会成为 root:

      # sudo -s
      # ls -hal /root/ > /root/test.out
      # exit
      

      这可能不是最好的方法,但它确实有效。

      【讨论】:

        【解决方案5】:

        也许您只获得了对某些程序/路径的 sudo 访问权限?那么就没有办法做你想做的事了。 (除非你会以某种方式破解它)

        如果不是这样,那么也许你可以编写 bash 脚本:

        cat > myscript.sh
        #!/bin/sh
        ls -hal /root/ > /root/test.out 
        

        ctrl + d :

        chmod a+x myscript.sh
        sudo myscript.sh
        

        希望对您有所帮助。

        【讨论】:

          【解决方案6】:

          这里有人刚刚建议 sudoing tee:

          sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null
          

          这也可用于将任何命令重定向到您无权访问的目录。它之所以有效,是因为 tee 程序实际上是一个“回显到文件”程序,重定向到 /dev/null 是为了阻止它也输出到屏幕,以保持它与上面的原始人为示例相同。

          【讨论】:

          • 在许多情况下,即如果普通用户有权执行命令并且“仅”无法写入所需的输出文件,则第一个sudo(即,对于命令本身)可能是省略
          【解决方案7】:

          问题是 commandsudo 下运行,但 redirection 在您的用户下运行。这是由 shell 完成的,您几乎无能为力。

          sudo command > /some/file.log
          `-----v-----'`-------v-------'
             command       redirection
          

          绕过这个的通常方法是:

          • 将命令包装在您在 sudo 下调用的脚本中。

            如果命令和/或日志文件更改,您可以使 脚本将这些作为参数。例如:

            sudo log_script command /log/file.txt
            
          • 调用shell并将命令行作为参数传递给-c

            这对于一次性复合命令特别有用。 例如:

            sudo bash -c "{ command1 arg; command2 arg; } > /log/file.txt"
            
          • 安排具有所需权限的管道/子外壳(即 sudo)

            # Read and append to a file
            cat ./'file1.txt' | sudo tee -a '/log/file.txt' > '/dev/null';
            
            # Store both stdout and stderr streams in a file
            { command1 arg; command2 arg; } |& sudo tee -a '/log/file.txt' > '/dev/null';
            

          【讨论】:

            【解决方案8】:

            我自己发现的一个技巧是

            sudo ls -hal /root/ | sudo dd of=/root/test.out
            

            【讨论】:

            • sudo dd 比上面的 sudo tee /root/file > /dev/null 示例更好!
            • dd 不是一个奇怪的晦涩命令。当您需要在两个块设备之间通过缓冲复制大量数据时使用它。语法其实很简单,dd 是命令名,of=/root/test.out 是告诉dd 输出文件是什么的参数。
            • @steve 在您了解它是什么之前,一切都是“晦涩难懂”的。 of 表示 输出文件dd 是 Linux 和 OSX 中非常流行的工具(主要用于将图像写入磁盘)。这肯定是一个巧妙的技巧。
            • dd 在这里可能与tee 一样有用。在这两种情况下,您都在使用一个常见的、众所周知的命令,尽管与最初的预期目的略有不同,但它仍然是众所周知且有据可查的。虽然dd 擅长复制大量数据,但它并不擅长复制少量数据。它的好处是不将输出回显到标准输出。
            • 每当你一个接一个地输入单词sudo dd时,你要非常,非常确保后面的参数是正确的(特别是考虑到它的非标准语法)。他们不会无缘无故地称其为“磁盘破坏者”......
            【解决方案9】:

            我会这样做:

            sudo su -c 'ls -hal /root/ > /root/test.out'
            

            【讨论】:

            • 这实际上看起来更简洁一些,因为您不需要显式指定外壳。
            • 一个小缺点是它运行了一个额外的进程(su):$ sudo su -c 'pstree -sp $$ >/dev/fd/1'init(1)───gnome-terminal(6880)───bash(6945)───sudo(401)───su(402)───bash(410)───pstree(411)
            【解决方案10】:

            主题的另一种变化:

            sudo bash <<EOF
            ls -hal /root/ > /root/test.out
            EOF
            

            当然也可以:

            echo 'ls -hal /root/ > /root/test.out' | sudo bash
            

            它们有一个(微小的)优势,您不需要记住 sudosh/bash 的任何参数

            【讨论】:

              【解决方案11】:

              澄清一下为什么 tee 选项更可取

              假设您具有执行创建输出的命令的适当权限,如果您将命令的输出通过管道传输到 tee,则只需使用 sudo 提升 tee 的权限并指示 tee 写入(或附加)到文件问题。

              在问题中给出的示例中,这意味着:

              ls -hal /root/ | sudo tee /root/test.out
              

              举几个更实际的例子:

              # kill off one source of annoying advertisements
              echo 127.0.0.1 ad.doubleclick.net | sudo tee -a /etc/hosts
              
              # configure eth4 to come up on boot, set IP and netmask (centos 6.4)
              echo -e "ONBOOT=\"YES\"\nIPADDR=10.42.84.168\nPREFIX=24" | sudo tee -a /etc/sysconfig/network-scripts/ifcfg-eth4
              

              在每个示例中,您将获取非特权命令的输出并写入通常只能由 root 写入的文件,这是您问题的来源。

              这样做是个好主意,因为生成输出的命令不是以提升的权限执行的。 echo 在这里似乎无关紧要,但是当源命令是您不完全信任的脚本时,它至关重要。

              请注意,您可以使用 -a 选项将 tee 附加到目标文件(如 &gt;&gt;)而不是覆盖它(如 &gt;)。

              【讨论】:

              • 对不起 js3,但这已经被建议了(早在 2008 年)并且处于第二高的答案:stackoverflow.com/a/82553/6910
              • 你说得对,乔纳森,我会更新我的答案,以扩展为什么这是一个更好的选择的原因。感谢您提供有用的反馈。
              【解决方案12】:

              这是基于涉及tee 的答案。为了方便起见,我编写了一个小脚本(我称之为suwrite)并将其放入/usr/local/bin/ 并获得+x 许可:

              #! /bin/sh
              if [ $# = 0 ] ; then
                  echo "USAGE: <command writing to stdout> | suwrite [-a] <output file 1> ..." >&2
                  exit 1
              fi
              for arg in "$@" ; do
                  if [ ${arg#/dev/} != ${arg} ] ; then
                      echo "Found dangerous argument ‘$arg’. Will exit."
                      exit 2
                  fi
              done
              sudo tee "$@" > /dev/null
              

              如代码中的 USAGE 所示,您所要做的就是将输出通过管道传输到此脚本,然后是所需的超级用户可访问的文件名,如果出现以下情况,它将自动提示您输入密码需要(因为它包括sudo)。

              echo test | suwrite /root/test.txt
              

              请注意,由于这是tee 的简单包装器,因此它还将接受 tee 的 -a 选项进行追加,并且还支持同时写入多个文件。

              echo test2 | suwrite -a /root/test.txt
              echo test-multi | suwrite /root/test-a.txt /root/test-b.txt
              

              它还具有一些简单的保护措施,防止写入/dev/ 设备,这是本页的一个 cmets 中提到的一个问题。

              【讨论】:

                【解决方案13】:

                解决这个问题的方法是:

                如果需要写入/替换文件:

                echo "some text" | sudo tee /path/to/file
                

                如果需要追加到文件中:

                echo "some text" | sudo tee -a /path/to/file
                

                【讨论】:

                • 这与上面的答案有何本质不同?
                • 它不是“完全不同”,但它阐明了替换和附加到文件之间的独特用法。
                • 这是我复制到备忘单上的答案。
                【解决方案14】:

                并不是要打死马,但是这里有太多的答案使用tee,这意味着你必须将stdout重定向到/dev/null,除非你想在屏幕上看到一个副本。

                一个更简单的解决方案是像这样使用cat

                sudo ls -hal /root/ | sudo bash -c "cat > /root/test.out"
                

                注意重定向是如何放在引号内的,以便它由sudo 启动的shell 评估,而不是运行它的shell。

                【讨论】:

                • 这很好用。我不明白为什么它有一张反对票。赞成。
                • 我认为它并没有得到太多的爱,因为它并不比sudo bash -c "ls -hal /root &gt; /root/test.out"好多少。使用 tee 可以避免需要 shell,而 cat 不需要。
                【解决方案15】:
                sudo at now  
                at> echo test > /tmp/test.out  
                at> <EOT>  
                job 1 at Thu Sep 21 10:49:00 2017  
                

                【讨论】:

                • 如果你有sudoat 没有用或没有必要。 sudo sh -c 'echo test &gt;/tmp/test.out' 更高效、更优雅地执行相同的操作(但仍然存在缺陷,即您可能正在运行不需要该特权的 root 的东西;您通常应该尽可能避免使用特权命令)。
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2016-12-28
                • 2015-08-14
                • 2011-04-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多