用于全局扩展的未加引号变量中的反斜杠

用于全局扩展的未加引号变量中的反斜杠

鉴于这六个文件:

$ touch  'sec*et'  'sec\*et'  'sec\et'   secet   secret  'sec\ xxx et'

为什么用于全局扩展的未加引号变量中的反斜杠仅匹配sec\*et文件?

$ v="sec\*et" ; ls $v
'sec\*et'
$ v='sec\*et' ; ls $v
'sec\*et'

与此相关所以答案, 这POSIX 定义:

< 反斜杠 > 应保留其作为转义字符的特殊含义...仅当后跟以下字符之一时被认为是特殊的:

$ ` " \ <newline>

bash手册:

仅当反斜杠后跟以下字符之一时,反斜杠才保留其特殊含义:' $'、' `'、' "'、' \' 或换行符。在双引号内,后跟这些字符之一的反斜杠将被删除。前面没有特殊含义的反斜杠字符保持不变。

我知道变量中的反斜杠(星号之前)是字面反斜杠:

$ v='sec\*et' ; printf '%s' "$v" | hexdump -C
00000000  73 65 63 5c 2a 65 74                              |sec\*et|
00000007

但我不明白为什么通配符*在字面反斜杠之后失去了特殊含义。


我明白的三件事:

*(A)未加引号的变量中的星号在全局扩展中具有特殊含义。它们是等价的:

$ v='sec*et' ; ls $v
'sec*et'  'sec\*et'  'sec\et'   secet   secret  'sec\ xxx et'
$ ls sec*et
'sec*et'  'sec\*et'  'sec\et'   secet   secret  'sec\ xxx et'

(B) 星号*在反斜杠之后失去其特殊含义:

$ ls sec\*et
'sec*et'

(C) 字面上的反斜杠不能使星号*失去其特殊含义:

$ v='sec\\*et' ; ls $v
'sec\*et'  'sec\et'  'sec\ xxx et'
$ ls sec\\*et
'sec\*et'  'sec\et'  'sec\ xxx et'

这是我不明白的:

然而奇怪的是,星号失去其特殊含义,但反斜杠并未被丢弃, 在这种情况下:

$ v='sec\*et' ; ls $v
'sec\*et'

不知何故,它相当于一个字面反斜杠后跟一个字面星号:

$ ls sec\\\*et
'sec\*et'

但为什么?考虑:

  1. 如果引号中的特殊字符变成文字,则 (A) 不成立。

  2. 如果星号因为后面有反斜杠而变成文字,为什么反斜杠不会被丢弃,并匹配 file sec*et,就像 (B) 中那样?


在应用中,除了使用 Bracket Expression 之外[*],如何定义在 glob 扩展中使用时与文字星号匹配的字符串变量?

$ v='sec < what what what > et' ; ls $v
'sec*et'

答案1

$ v="sec\*et"
$ v='sec\*et'

其中任何一个都会将变量设置为sec\*et,并且变量获取其值的方式不会影响通配符的行为。

Bash 处理后续未加引号的扩展的方式似乎是,由于它没有未转义的 glob 字符,因此该字符串sec\*et不会被视为 glob根本不。它不会触发 eg failglob,并且反斜杠不会被删除。相反,它只是按原样打印。 (这不是模式匹配本身:即使没有该名称的文件,您也会返回字符串。)

sec[*]et这与一团。

另外,如果您要使用sec\*et*它,它将是一个 glob,并且会匹配以 开头的文件名sec*et(即删除反斜杠)。

据我所知,大多数版本的 Bash 都是这样工作的。 Bash 5.0 是个例外,它sec\*et被视为一个 glob,并且会触发例如failglob。

$ ./bash-4.4/bash    -c 'shopt -s failglob; v="sec\*et"; echo $v'
sec\*et

$ ./bash-5.0/bash    -c 'shopt -s failglob; v="sec\*et"; echo $v'
./bash-5.0/bash: no match: sec\*et

$ ./bash-5.1.16/bash -c 'shopt -s failglob; v="sec\*et"; echo $v'
sec\*et

$ ./bash-5.2.15/bash -c 'shopt -s failglob; v="sec\*et"; echo $v'
sec\*et

(我没有测试所有情况下的所有 shell 版本。)

相关内容