Bash 在什么情况下不执行分词和通配符?

Bash 在什么情况下不执行分词和通配符?

在这些情况下,Bash 不会在通配符中执行分词:

  • 赋值的 LHS 或 RHS,索引数组除外
    var=$value                                # simple variable
    declare -A hash
    key="key with a space"
    hash[$key]=$value                         # index of an associative array
    
    arr=$(echo "1 2 3")                       # word splitting does happen here
    
  • 里面[[ ]]
    var="one two"
    if [[ $var = *" "* ]]; then ...           # check if var has a space in it
    if [[ $(echo "one two") = $var ]]; then   # use the output of command substitution to compare with var
    
  • 里面(( ))
    ((sum = $(echo "99 + 1")))                  # assigns 100 to sum
    
  • 在此字符串中
    cat <<< *                                 # gives '*' as the output
    

是否有 Bash 执行或不执行分词和通配符的情况的明确列表?

答案1

这通常是它不能或没有意义的情况,所以非列表上下文。然而,在非列表上下文中,它会执行此操作,但当它导致多个项目或用空格连接这些项目时会发出抱怨。

此外,区分通配符模式匹配和文件名生成或通配符(生成与模式匹配的文件名列表)也很重要。

例如,在 中[[ foo = * ]],没有通配符,因为它*没有扩展到当前目录中的非隐藏文件列表,但*仍然被解释为模式(这里它返回 true 与模式foo匹配*)。

此处的拆分是指在未加引号的参数扩展 ( $param)、命令替换 ($(...)`...`) 以及算术扩展 ($((...))$[...]) 上完成的隐式拆分,使用$IFS中的特殊参数列出上下文

*下面我们就以这个例子为例。作为模式,它匹配任何字符序列。作为一个 glob,它扩展到当前目录中的所有非隐藏文件(受dotglob, GLOBIGNORE...)的影响。

以下适用于bash,其他 shell 存在变化。

不发生分割和通配符的情况:

  • 引用时(用'*', "*", \*, $'*', $"*")。

  • 在此处的文档中(无论分隔符是否被引用):

    cat << EOF
    *
    EOF
    cat << 'EOF'
    *
    EOF
    
  • 算术表达式内部:

    • echo $((2 * 2))*不是通配符,而是$((...))经过 split+glob,稍后尝试IFS=4
    • array[2 * 2]=4// ${array[2 * 2]}exec {array[2*2]}>&1​请注意, unset -v 'a[1]'([1]是通配符)中需要引号。
    • ((2 * 2))
    • echo $[2 * 2]
  • 标量变量赋值:

    • var=*
    • array[x]=*
    • hash[key]=*
    • array=([1]=*)(尽管旧版本过去常常在那里进行通配,并且例如在当前目录中bash调用一个文件时会执行不同的操作)。1=foo
    • var+=*
  • 在关联数组键中:

    • typeset -A hash; hash[**]=value; v=${hash[**]}*虽然@很特别。
  • //在赋值之后export//仅在某些情况下:赋值关键字和变量名不能被引用,即使是部分引用,也不能是任何扩展的结果。分配和重定向可能会发生在之前,但不能使用:localtypesetdeclarereadonly=command

    • 好的(没有 split+glob):
      • export a=*
      • x=1 < /dev/null export foo a=*
    • 不正常(执行 split+glob):
      • ""export a=*
      • command export a=*(POSIX 模式除外)
      • export "a"=*
      • export a\=*
      • "$(echo export)" a=*

    有关更多信息,请访问局部变量赋值需要引号吗?

  • case * in (...); esac

  • case x in (*); esac(没有 split+glob,但它*被视为一种模式,也适用于在未加引号的扩展中找到的通配符,如var=*; case x in ($var))。

  • 里面[[...]]。但请注意,如果=, ==,运算符的右侧存在未加引号的通配符,则会完成模式匹配!=

  • 从 4.4 版本开始这里的字符串。在早期版本中,进行了拆分(尽管不是通配符),并且生成的单词与空格连接。

  • 当 shell 处于 POSIX 模式且非交互时,在重定向的目标中:bash -o posix -c 'echo test > *'.否则,将执行 split+glob,bash如果扩展为少于或多于 1 个元素的列表,则会报告错误。

相关内容