【问题标题】:Is there a command-line shortcut for ">/dev/null 2>&1"">/dev/null 2>&1" 是否有命令行快捷方式
【发布时间】:2010-10-30 01:03:30
【问题描述】:

当我不想看到程序的输出时,输入这个真的很烦人。我很想知道是否有更短的写作方式:

$ program >/dev/null 2>&1

通用 shell 是最好的,但了解其他 shell 也会很有趣,尤其是 bash 或 dash。

【问题讨论】:

    标签: bash shell command redirect pipe


    【解决方案1】:
    >& /dev/null
    

    【讨论】:

    • 谢谢,那很好(不知道那个),但我应该指定“快捷方式”意味着少于一半的字符数。这几乎和打字一样多。实际上 2>&1 部分很简单,就是 /dev/null 输入起来很烦人。
    • 我真的很想知道您正在运行什么,它迫使您将 stdout 和 stderr 频繁地通过管道传输到 /dev/null,以至于键入 /dev/null 变得很烦人。
    • Bash 手册更喜欢“&>/dev/null”形式,以避免与“>&n”(其中 n 是整数)可能产生的歧义。不过,我不认为它在 Bash 之外是可移植的。
    【解决方案2】:

    你可以为此编写一个函数:

    function nullify() {
      "$@" >/dev/null 2>&1
    }
    

    要使用这个功能:

    nullify program arg1 arg2 ...
    

    当然,您可以随意命名函数。例如,它可以是单个字符。

    顺便说一句,您可以使用execstdoutstderr 临时重定向到/dev/null。我不知道这对您的情况是否有帮助,但我想分享一下。

    # Save stdout, stderr to file descriptors 6, 7 respectively.
    exec 6>&1 7>&2
    # Redirect stdout, stderr to /dev/null
    exec 1>/dev/null 2>/dev/null
    # Run program.
    program arg1 arg2 ...
    # Restore stdout, stderr.
    exec 1>&6 2>&7
    

    【讨论】:

    • 这应该是公认的答案,我尝试自己实现,但由于某种原因我不小心在子shell 中运行了“$@”。这对我来说完美无缺。
    【解决方案3】:

    bashzshdash 中:

    $ program >&- 2>&-
    

    它也可能出现在其他 shell 中工作,因为 &- 是一个错误的文件描述符。

    请注意,此解决方案会关闭文件描述符,而不是将它们重定向到 /dev/null,这可能会导致程序中止。

    【讨论】:

    • “可能”?我称之为“通常会”。不检查其写入是否成功的程序是buggy
    • 如果我是对的,sh 是给定发行版的默认 shell 的名称,而 dash 是 Debian 版本的名称 ash。见wikipedia。你能澄清一下吗?
    • @loxaxs:在 Ubuntu 中,sh 现在运行 dash。我不记得在撰写本文时它对我做了什么(我似乎记得在 POSIX 兼容模式下运行 bash 的一些事情),但由于模棱两可,我现在已经删除了它。
    【解决方案4】:

    大多数 shell 都支持别名。例如,在我的 .zshrc 我有类似的东西:

    alias -g no='2> /dev/null > /dev/null' 
    

    然后我就输入

    program no
    

    【讨论】:

    • 在 bash 中,应该是: alias no='2> /dev/null > /dev/null';没有命令 arg arg
    【解决方案5】:

    如果/dev/null 输入过多,您可以(以 root 身份)执行以下操作:

    ln -s /dev/null /n
    

    那么你可以这样做:

    program >/n 2>&1
    

    当然,如果不先设置符号链接,您以这种方式编写的脚本将无法移植到其他系统。

    【讨论】:

    • 结合上面的答案,我想我可以做到:program &>/n 相当不错。谢谢!
    • 应该是程序 >&/n
    【解决方案6】:

    同样值得注意的是,通常重定向输出并不是真正需要的。许多 Unix 和 Linux 程序接受一个“静默标志”,通常是 -n-q,它禁止任何输出并且只在成功或失败时返回一个值。

    例如

    grep foo bar.txt >/dev/null 2>&1
    if [ $? -eq 0 ]; then
         do_something
    fi
    

    可以改写为

    grep -q foo bar.txt
    if [ $? -eq 0 ]; then
         do_something
    fi
    

    【讨论】:

    • 不必要地检查 $? 是不好的形式,而不是 if grep -q foo bar.txt; then - 它会使您的代码变得脆弱,因此如果有人执行此类日志检测,新添加的日志行可能会破坏您的测试t 谨慎对待 $? 预计保持不变的位置。
    【解决方案7】:

    编辑:基于(:)|: 的解决方案可能会导致错误,因为: 不会读取stdin。虽然它可能不像 Zaz 的回答中所建议的那样关闭文件描述符那么糟糕。


    • 对于 bash 和 bash 兼容的 shell (zsh...):

      $ program &>/dev/null
      OR
      $ program &> >(:) # Should actually cause error or abortion
      
    • 对于所有贝壳:

      $ program 2>&1 >/dev/null
      OR
      $ program 2>&1|: # Should actually cause error or abortion
      

      $ program 2>&1 > >(:)对dash无效,因为它拒绝操作文件替换的进程替换权。

    解释:

    • 2>&1 将 stderr(文件描述符 2)重定向到 stdout(文件描述符 1)。
    • | 是标准输出到另一个命令的标准输入的常规管道。
    • : 是一个不做任何事情的内置 shell(相当于 true)。
    • &> 将 stdout 和 stderr 输出重定向到文件。
    • >(your-command) 是进程替换。它被替换为特殊文件的路径,例如:/proc/self/fd/6。此文件用作命令your-command 的输入文件。

    注意:尝试写入已关闭文件描述符的进程将收到EBADF(错误文件描述符)错误,这比尝试写入| true 更有可能导致中止。后者会导致 EPIPE(管道)错误,请参阅 Charles Duffy 的评论。

    【讨论】:

    • 我不会说“等效”; >&- 实际上关闭了描述符,并且行为是相当不同的(写入关闭的,因此不存在的 FD 会导致不同的,更可能是致命的错误)。跨度>
    • 比较python -c 'print "hello"' >&-python -c 'print "hello"' | truepython -c 'print "hello"' > /dev/null
    • ... | true 返回EPIPE,而>&- 返回EBADF——两个完全不同的错误。 Python 运行时不能有效地区分它们既不是这里也不是那里。
    【解决方案8】:

    Ayman Hourieh's solution 适用于一次性调用过于繁琐的程序。但是,如果您想要抑制输出的只有一小部分常用程序,请考虑通过将以下内容添加到您的 .bashrc 文件(或等效文件,如果您使用另一个 shell)来使它们静音:

    CHATTY_PROGRAMS=(okular firefox libreoffice kwrite)
    for PROGRAM in "${CHATTY_PROGRAMS[@]}"
    do
        printf -v eval_str '%q() { command %q "$@" &>/dev/null; }' "$PROGRAM" "$PROGRAM"
        eval "$eval_str"
    done
    

    这样您可以继续使用它们通常的名称调用程序,但它们的 stdout 和 stderr 输出将消失在位桶中。

    另请注意,某些程序允许您配置它们发出多少日志记录/调试输出。对于 KDE 应用程序,您可以运行 kdebugdialog 并选择性地或全局禁用调试输出。

    【讨论】:

    • 为什么要像使用列表一样使用字符串?如果您正在编写本机 bash (并且使用 function 关键字意味着您的代码不是 trying 可移植的;POSIX ),那么您肯定有数组; chatty_programs=( okular firefox whatever ); for program in "${chatty_programs[@]}"; do;这样你的代码就不会依赖于 IFS 的当前值。
    • 我也会考虑让 shell 为你执行引用:printf -v eval_str '%q() { command %q "$@" &>/dev/null; }' "$program" "$program"; eval "$eval_str"——这样如果有人借用这个成语并用他们无法控制的输入名称运行它,一些小丑会创建一个脚本命名为 $(rm -rf ~) (是的,这是一个有效的文件名 - 如果尝试创建它,请务必使用单引号)不会让他们度过糟糕的一天。
    • @CharlesDuffy:你是对的;感谢您提出的改进建议。我已经相应地修改了我的答案。
    • +1。也就是说,关于:变量命名约定,请参阅pubs.opengroup.org/onlinepubs/9699919799/basedefs/…,第四段——全大写名称用于对 POSIX 指定的工具(操作系统或外壳)有意义的变量,而其他名称保留用于应用程序命名空间并保证不要改变 POSIX 指定工具的行为。因此,避免使用全部大写不仅有助于避免无意覆盖 PATH 等,还有助于避免无意更改尚未引入的 shell 内部变量。
    【解决方案9】:

    在我看来,最便携的解决方案和最佳答案将是您终端 (PC) 上的宏。

    这样,无论您登录到哪个服务器,它都会一直存在。

    如果您碰巧运行 Windows,则可以通过 AHK(谷歌搜索,它是开源的)在两行代码中获得所需的结果。这可以将任何键串原位转换成任何其他键串。

    您输入“ugly.sh >>NULL”,它会将其重写为“ugly.sh 2>&1 > /dev/null”或其他什么。

    其他平台的解决方案有些困难。 AppleScript 可以粘贴到键盘按下,但不能那么容易触发。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-27
      • 1970-01-01
      • 2013-04-29
      • 2021-11-11
      相关资源
      最近更新 更多