在 bash 中:变量替换中的尾随空格捕获

U. *_*ndl 0 bash variable-substitution

我在 BASH 4.3.48 (SLES12 SP4) 和 BASH 4.4.23 (OpenSUSE Leap 15.1) 中尝试从变量值中删除多个尾随空格时看到了这一点:

~> xxx="-O -Wall  "
~> echo "X${xxx%% }X"    # (1)
X-O -Wall X
~> echo "X${xxx%% *}X"
X-OX
~> echo "X${xxx% }X"
X-O -Wall X
~> echo "X${xxx% *}X"    # (2)
X-O -Wall X
~> echo "X${xxx%% \*}X"
X-O -Wall  X
Run Code Online (Sandbox Code Playgroud)

我觉得要么(1)或者(2)应该做这份工作。

手册规定${parameter%%word}

删除匹配的后缀模式。这个词被扩展以产生一个模式,就像在路径名扩展中一样。如果模式匹配参数扩展值的尾随部分,则扩展的结果是具有最短匹配模式(“%”情况)或最长匹配模式(“%”)的参数扩展值%'' 大小写)已删除。

由于它不像文档那样工作(或者我理解文档),我怀疑这是一个错误(在 BASH 的-Wall情况下,将删除不匹配的后缀(“ ”)%% *。我对吗?

row*_*oat 6

在后缀删除中使用前缀删除:

$ xxx="-O -Wall  "
$ echo "X${xxx%"${xxx##*[! ]}"}X"
X-O -WallX
Run Code Online (Sandbox Code Playgroud)
  • 删除最后一个非空格字符之前的所有内容 - 只留下尾随空格
  • 使用这些空格作为去除后缀的模式
  • 应该引用内部参数扩展以防止它被解释为模式(上面不是必需的,但在其他情况下可能有用):
$ xxx="-O -Wall  "
$ echo "X${xxx%"${xxx##*[! ]}"}X"
X-O -WallX
Run Code Online (Sandbox Code Playgroud)

一个人为的例子,但如果没有引用内部扩展,它包含的星号将被外部扩展视为壳模式。引用,它变成了字面的星号。


您观察到的行为不是错误,只是 shell 模式的工作方式很简单:

${xxx%% }
Run Code Online (Sandbox Code Playgroud)
  • 一个空间就是一个空间
  • 单个空格的最长出现是单个空格
${xxx%% *}
Run Code Online (Sandbox Code Playgroud)
  • 单个空格的最长出现时间,后跟任何/无
  • 任何/什么都不会包括 -Wall
${xxx% }
Run Code Online (Sandbox Code Playgroud)
  • 单个空格的最短出现是单个空格
${xxx% *}
Run Code Online (Sandbox Code Playgroud)
  • 单个空格后跟任何/无的最短出现是单个空格
${xxx%% \*}
Run Code Online (Sandbox Code Playgroud)
  • \* 是一个反斜杠转义星号,将被解释为文字星号
  • 变量中没有后跟星号的空格,没有删除后缀

  • @U.Windl 总是最好引用(除非您非常了解自己在做什么),以避免将字符串中的 glob 字符(*、?、[)解释为:“globbing characters”。 (2认同)