当在子shell或函数中设置了"extglob"选项时,Bash脚本抛出语法错误 [英] Bash script throws syntax errors when the 'extglob' option is set inside a subshell or function

查看:65
本文介绍了当在子shell或函数中设置了"extglob"选项时,Bash脚本抛出语法错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

子外壳:

/tmp/foo.sh: line 7: syntax error near unexpected token `('

#!/usr/bin/env bash
set -euo pipefail
(
    shopt -s extglob
    for f in ?(.)!(|+(.)|vendor); do
        echo "$f"
    done
)

函数内,它以相同的方式失败:

It fails in the same manner inside a function:

#!/usr/bin/env bash
set -euo pipefail

list_no_vendor () {
    shopt -s extglob
    for f in ?(.)!(|+(.)|vendor); do
        echo "$f"
    done
}

list_no_vendor

调查

在这两种情况下,当在子外壳程序或函数的外部中全局设置选项时,脚本都会成功执行.

Investigation

In both cases, the script executes successfully when the option is set globally, outside of the subshell or function.

令人惊讶的是,当在本地设置时,'extglob'选项似乎在子外壳程序和功能中均被有效启用:

Surprisingly, when set locally, the 'extglob' option appears to be effectively enabled in both the subshell and function:

#!/usr/bin/env bash
set -euo pipefail

(
    shopt -s extglob
    echo 'In the subshell:' "$(shopt extglob)"
)

list_no_vendor () {
    shopt -s extglob
    echo 'In the function:' "$(shopt extglob)"
}

echo 'In the main shell:' "$(shopt extglob)"

list_no_vendor

输出:

In the subshell: extglob            on
In the main shell: extglob          off
In the function: extglob            on

这使语法错误令我极为困惑.

This makes the syntax error extremely puzzling to me.

将Heredoc传递给 bash 命令有效.

Passing a heredoc to the bash command works.

#!/usr/bin/env bash
set -euo pipefail

bash <<'EOF'
    shopt -s extglob
    echo 'In the child:' "$(shopt extglob)"
EOF

echo 'In the parent:' "$(shopt extglob)"

输出:

In the child: extglob           on
In the parent: extglob          off

但是,我很想了解这里的问题要点.

However I would be curious to understand the gist of the problem here.

推荐答案

extglob 是解析器使用的标志.功能,复合命令和& c.会在执行之前完整解析.因此,必须在解析内容之前,在 之前设置 extglob .在执行时设置它,但在解析后设置,对于先前解析的内容没有任何作用.

extglob is a flag used by the parser. Functions, compound commands, &c. are parsed in entirety ahead of execution. Thus, extglob must be set before that content is parsed; setting it at execution time but after parse time does not have any effect for previously-parsed content.

这也是为什么您无法运行 shopt -s extglob;ls!(*.txt)作为单行代码(以前未设置 extglob 时),但是两个命令之间必须有换行符.

This is also why you can't run shopt -s extglob; ls !(*.txt) as a one-liner (when extglob is previously unset), but must have a newline between the two commands.

不是作为可接受做法的示例,而是作为演示行为的示例,请考虑以下内容:

Not as an example of acceptable practice, but as an example demonstrating the behavior, consider the following:

#!/usr/bin/env bash
(
    shopt -s extglob
    # Parse of eval'd code is deferred, so this succeeds
    eval '
        for f in ?(.)!(|+(.)|vendor); do
            echo "$f"
        done
    '
)

这里没有发生此类错误,因为解析传递给 eval 的内容仅在执行 shopt -s extglob 后的之后发生,而不是解析要在子shell中运行的代码块时.

No such error takes place here, because parsing of the content passed to eval happens only after the shopt -s extglob was executed, rather than when the block of code to be run in a subshell is parsed.

这篇关于当在子shell或函数中设置了"extglob"选项时,Bash脚本抛出语法错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆