AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / ubuntu / 问题 / 1168750
Accepted
WinEunuuchs2Unix
WinEunuuchs2Unix
Asked: 2019-08-27 16:51:14 +0800 CST2019-08-27 16:51:14 +0800 CST 2019-08-27 16:51:14 +0800 CST

如何将 2>/dev/null 作为变量传递?

  • 772

我有这个有效的代码:

# Hide irrelevant errors so chrome doesn't email us in cron
if [[ $fCron == true ]] ; then
    google-chrome --headless --disable-gpu --dump-dom \
        "$RobWebAddress" > "$DownloadName" 2>/dev/null
else
    # Get silly error messages when running from terminal
    google-chrome --headless --disable-gpu --dump-dom \
        "$RobWebAddress" > "$DownloadName"
fi

如果我尝试像这样缩短它:

# Hide irrelevant errors so chrome doesn't email us in cron
local HideErrors
[[ $fCron == true ]] && HideErrors="2>/dev/null"

google-chrome --headless --disable-gpu --dump-dom \
    "$RobWebAddress" > "$DownloadName" "$HideErrors"

我收到错误消息:

[0826/043058.634775:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
[0826/043058.672587:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
[0826/043058.711640:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
(... SNIP ...)

为什么硬编码的参数可以工作,但不能将参数作为变量?


编辑2:

目前,我通过第二个答案的替代建议找到了成功:

# Redirect errors when cron is used to /dev/null to reduce emails
ErrorPipe=/dev/stderr
[[ $fCron == true ]] && ErrorPipe=/dev/null

google-chrome --headless --disable-gpu --dump-dom \
                "$RobWebAddress" > "$DownloadName" 2>"$ErrorPipe"

编辑1:

基于第一个答案,我应该指出程序头已经包含:

[[ $fCron != true ]] &&
    exec 2> >(grep -v 'GtkDialog mapped without a transient parent' >&2)
command-line bash redirect
  • 3 3 个回答
  • 5349 Views

3 个回答

  • Voted
  1. Best Answer
    Eliah Kagan
    2019-08-27T17:27:42+08:002019-08-27T17:27:42+08:00

    不能通过扩展导致重定向发生的原因是,在参数扩展产生后,不会对"$HideErrors"符号进行特殊处理。这实际上非常好,因为这些符号出现在您可能希望按字面扩展和使用的文本中。>

    无论您是否引用,这都成立$HideErrors。参数扩展的结果会在扩展不加引号时进行分词和通配,但仅此而已。


    至于怎么做,有很多方法可以实现条件重定向。对于一个非常简单的命令,将整个命令编写两次可能是合理的,一次在caseor if-else构造的每个分支中。但是,这很快就会变得繁琐,而您显示的命令肯定是不理想的情况。

    在让您避免重复自己的方法中,我特别推荐两种方法,因为它们非常干净且易于正确处理。您只想使用其中之一,而不是同时使用相同的命令和重定向。

    存储命令而不是重定向。与其尝试将重定向存储在变量中并应用参数扩展,不如将命令存储在shell 函数中。然后写一个caseor if- else,其中函数在一个分支上调用重定向,而在另一个分支上没有重定向。

    如果您将命令概念化为您想编写一次但在多种情况下运行的代码,那么函数是自然的解决方案。这是我通常做的。它的好处是既不需要子shell,也不需要手动存储和重置状态。

    使用您的代码:

    launch() {
        google-chrome --headless --disable-gpu --dump-dom \
            "$RobWebAddress" > "$DownloadName"
    }
    
    case $fCron in
    true)  launch 2>/dev/null;;
    *)     launch;; # Get silly error messages when running from terminal
    esac
    

    您可以应用您喜欢的任何间距,或者if-else如果您愿意的话。请注意,即使它们是局部变量,它也会launch自动使用调用者RobWebAddress和变量,因为 Bash 是动态作用域的,这与大多数具有词法作用域的编程语言不同。DownloadName

    在子 shell 中运行命令并有条件地将重定向应用到exec. 这是steeldriver 评论的,但在内部( )保持效果局部。当内置函数不带参数运行时,exec它不会用新进程替换当前 shell,而是将其任何重定向应用到当前 shell。

    (也可以跟踪什么是标准错误并恢复它,而无需使用子外壳,因此不会牺牲修改当前外壳环境的能力。不过,我会将其细节留给其他答案。)

    使用您的代码:

    (
        # Suppress silly error messages unless running from terminal
        case $fCron in true) exec 2>/dev/null;; esac
    
        google-chrome --headless --disable-gpu --dump-dom \
            "$RobWebAddress" > "$DownloadName"
    )
    

    关闭之后),标准错误实际上恢复到以前的状态,因为它只是在子shell中真正被重定向,而不是在父shell中。这也适用于现有的 shell 变量,因为子 shell 会获得这些变量的副本。虽然我更喜欢使用 shell 函数,但我承认这种方法可能需要更少的代码。

    无论文件或设备标准错误以什么开始,这两种方法都有效,包括应用于调用包含条件行为的代码的 shell 函数的重定向,以及标准错误的情况(在您的编辑中提到)整个脚本已经被以前的or重定向了。路径是由进程替换产生的,这没有问题。exec 2>&fdexec 2> path

    • 20
  2. ilkkachu
    2019-08-28T07:18:53+08:002019-08-28T07:18:53+08:00

    为什么硬编码的参数可以工作,但不能将参数作为变量?

    因为语法项不是从扩展的变量值中解释的。也就是说,变量扩展与在命令行中将变量引用替换为变量的文本不同。(像;,|和&&引号之类的东西在变量的值中也不是特别的。)

    你可以做的是使用别名,或者使用变量来保存重定向的目标。

    别名只是文本替换,因此它们可以包含句法项,例如运算符和关键字。在脚本中,您需要shopt expand_aliases,因为默认情况下它们在非交互式 shell 中被禁用。所以,这打印2(仅):

    #!/bin/bash
    shopt -s expand_aliases
    
    alias redir='> /dev/null'
    redir echo 1
    alias redir=''
    redir echo 2
    

    (你也可以alias jos=if niin=then soj=fi用芬兰语写下你所有的 if 语句。我相信任何阅读脚本的人都会喜欢你。)

    或者,始终编写重定向,但仅使用变量控制目标。在您不想更改输出位置的情况下,您需要一个无操作目标,但/dev/stderr在这种情况下应该可以工作。实际上,添加2> /dev/stderr并不是一个空操作,因为 Linux 将打开的 fd/proc/<pid>/fd视为独立于原始文件的方式。这会影响写入位置的定位,如果输出到常规文件,则会弄乱输出。

    不过,它应该在附加模式下工作(或者如果 stderr 进入管道或终端):

    #!/bin/sh
    exec 2>/tmp/error.log
    dst=/dev/null
    ls -l /nosuchfile-1 2>> "$dst"     # this doesn't print
    dst=/dev/stderr
    ls -l /nosuchfile-2 2>> "$dst"
    ls -l /nosuchfile-3 2>> "$dst"
    

    所以重复一遍:2> /dev/stderr可以打破。

    • 5
  3. Joshua
    2019-08-28T18:04:44+08:002019-08-28T18:04:44+08:00

    问题标题:“如何将 2>/dev/null 作为变量传递?” 这实际上可以使用eval

    joshua@nova:/tmp$ X=">/dev/null"
    joshua@nova:/tmp$ echo $X
    >/dev/null
    joshua@nova:/tmp$ eval echo $X
    joshua@nova:/tmp$ eval echo hi
    hi
    joshua@nova:/tmp$ eval echo hi $X
    joshua@nova:/tmp$ echo hi $X
    hi >/dev/null
    joshua@nova:/tmp$ 
    

    所以我们可以重写为

    # Hide irrelevant errors so chrome doesn't email us in cron
    local HideErrors
    local RobWebAddress2
    local DownloadName2
    [[ $fCron == true ]] && HideErrors="2>/dev/null"
    RobWebAddress2='"$RobWebAddress"'
    DownloadName2='>"$DownloadName"'
    
    eval google-chrome --headless --disable-gpu --dump-dom \
        $RobWebAddress2 $DownloadName2 "$HideErrors"
    

    间接变量访问可防止在命令行的其余部分过早发生扩展。

    变量中的双引号工作得很好。

    joshua@nova:/tmp$ X='"'
    joshua@nova:/tmp$ Y='$X'
    joshua@nova:/tmp$ eval echo $Y
    "
    joshua@nova:/tmp$ 
    
    • 2

相关问题

  • 如何从命令行仅安装安全更新?关于如何管理更新的一些提示

  • 如何从命令行刻录双层 dvd iso

  • 如何从命令行判断机器是否需要重新启动?

  • 文件权限如何工作?文件权限用户和组

  • 如何在 Vim 中启用全彩支持?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何运行 .sh 脚本?

    • 16 个回答
  • Marko Smith

    如何安装 .tar.gz(或 .tar.bz2)文件?

    • 14 个回答
  • Marko Smith

    如何列出所有已安装的软件包

    • 24 个回答
  • Marko Smith

    无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗?

    • 25 个回答
  • Martin Hope
    Flimm 如何在没有 sudo 的情况下使用 docker? 2014-06-07 00:17:43 +0800 CST
  • Martin Hope
    Ivan 如何列出所有已安装的软件包 2010-12-17 18:08:49 +0800 CST
  • Martin Hope
    La Ode Adam Saputra 无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗? 2010-11-30 18:12:48 +0800 CST
  • Martin Hope
    David Barry 如何从命令行确定目录(文件夹)的总大小? 2010-08-06 10:20:23 +0800 CST
  • Martin Hope
    jfoucher “以下软件包已被保留:”为什么以及如何解决? 2010-08-01 13:59:22 +0800 CST
  • Martin Hope
    David Ashford 如何删除 PPA? 2010-07-30 01:09:42 +0800 CST

热门标签

10.10 10.04 gnome networking server command-line package-management software-recommendation sound xorg

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve