代码之家  ›  专栏  ›  技术社区  ›  gcb

bash循环命令中的引号如何影响控制流?

  •  1
  • gcb  · 技术社区  · 4 月前

    看到一些让我质疑自己理智的事情:

    #!/bin/env bash
    set -e
    for d in '/tmp/somedir/*'; do               
        for f in "${d}/*pub"; do
            echo $f;
        done
    done
    

    它按预期返回

    /tmp/somedir/AAA/fileaa.pub /tmp/somedir/BBB/filebb.pub

    但是,如果我改变 echo $f echo "$f" echo "${f}" 我得到:

    /tmp/somedir/*/*pub

    我很难理解为什么。对于初学者来说,这是一个单一的项目,所以它不仅仅影响 echo 线。

    使用 GNU bash, version 5.2.37(1)-release (x86_64-pc-linux-gnu)

    这是那个主机上的商店

    assoc_expand_once       off
    cdable_vars     off
    cdspell         off
    checkhash       off
    checkjobs       off
    checkwinsize    on
    cmdhist         on
    compat31        off
    compat32        off
    compat40        off
    compat41        off
    compat42        off
    compat43        off
    compat44        off
    complete_fullquote      on
    direxpand       off
    dirspell        off
    dotglob         off
    execfail        off
    expand_aliases  on
    extdebug        off
    extglob         on
    extquote        on
    failglob        off
    force_fignore   on
    globasciiranges on
    globskipdots    on
    globstar        off
    gnu_errfmt      off
    histappend      on
    histreedit      off
    histverify      off
    hostcomplete    off
    huponexit       off
    inherit_errexit off
    interactive_comments    on
    lastpipe        off
    lithist         off
    localvar_inherit        off
    localvar_unset  off
    login_shell     off
    mailwarn        off
    no_empty_cmd_completion off
    nocaseglob      off
    nocasematch     off
    noexpand_translation    off
    nullglob        off
    patsub_replacement      on
    progcomp        on
    progcomp_alias  off
    promptvars      on
    restricted_shell        off
    shift_verbose   off
    sourcepath      on
    varredir_close  off
    xpg_echo        off
    
    1 回复  |  直到 4 月前
        1
  •  2
  •   Feng    4 月前
    #!/bin/env bash
    set -e
    for d in '/tmp/somedir/*'; do # `*` and `?` should not be quoted unless they exist in the filenames
        for f in "${d}/*pub"; do
            echo $f; # Here, the variable `f` is actually `/tmp/somedir/*/*pub`
                     # Without double quotes, Bash will expand the glob at this point
                     # So, you will see all matching files.
                     # With double quotes, you will see the original value of var `f`
        done
    done
    

    更正脚本后:

    #!/bin/env bash
    set -e
    for d in /tmp/somedir/*; do               
        for f in "${d}"/*pub; do # only quote the variable
            echo "$f"; # you will get each filename
        done
    done
    

    通常,我们不应该引用 * ? 消息灵通的这样,Bash将展开它们以匹配每个文件名,for循环将按预期运行。