space 是 BASH 模式替换的特例吗?

Is space special for pattern replacement in BASH?

尝试使用 BASH 从变量的值中删除前导和尾随空白 (SPC),我觉得它不能像描述的那样工作。 我从 ${var%% }${var## } 开始,它们应该删除最长的模式,但似乎只删除了一个空白:

% val="  a  ";echo "|${val}|${val## }|"
|  a  | a  |
% val="  a  ";echo "|${val}|${val%% }|"
|  a  |  a |

然后我尝试了模式匹配,似乎没有删除任何内容(他们还应该重复删除值开头或结尾的空白):

% val="  a  ";echo "|${val}|${val//# }|"
|  a  |  a  |
% val="  a  ";echo "|${val}|${val//% }|"
|  a  |  a  |

我觉得我犯了一些简单的错误,但似乎我正坐在我的眼睛上:为什么这行不通?

(我确实已经访问过这些答案,但它们不包括 "my solution": How to trim whitespace from a Bash variable?, How to remove space from string?)

您可以使用 sed 将其归档。

删除字符串末尾的所有前导空 space 和空 space ...

sed 's/^[ \t]*//;s/[ \t]*$//'

Space (0x20) 对于 glob 模式和 RE 模式都不是特殊的。

对于您的问题,我会利用 extglob shell 选项:

[STEP 108] # shopt -s extglob
[STEP 109] # v='    foo    '
[STEP 110] # echo "|${v##+( )}|"
|foo    |
[STEP 111] # echo "|${v%%+( )}|"
|    foo|
[STEP 112] # echo "|${v%%+([[:blank:]])}|"
|    foo|
[STEP 113] # echo "|${v##+([[:blank:]])}|"
|foo    |
[STEP 114] #

问题不在于space (SPC) 被特殊处理;相反,问题是 bash 的手册页中使用的 pattern 指的是 pathname patterns,而不是 正则表达式(除非设置了extglob(这似乎是默认设置的))。那就是 ' *' 不是 空格序列 ,而是 后面跟任何东西的空格

第二个问题是“最长匹配模式”不是通过重复应用匹配直到失败来确定的,而是只有一次。因此,如果模式不包含 *%%% 会产生相同的结果,就像 ### 一样)。

${val//# }中的问题是:

  • ///#不能合并;只能使用一种变体。

  • pattern in ${parameter/pattern/string} 不是正则表达式,而是 pathname pattern(仍然) .

这意味着使用 ${val/# } 并没有比使用 ${val# }。要删除所有前导和尾随空白,可以使用以下(有点复杂)代码:

val="  a  "
echo -n "|${val}"
while [ "_$val" != "_${val# }" ]
do
    val="${val# }"
done
while [ "_$val" != "_${val% }" ]
do
    val="${val% }"
done
echo "|${val}|"

所以当使用 extglob 时,解决方案看起来像这样(正如之前的回答中指出的那样):

al="  c  "
echo -n "|${val}"
val="${val##+( )}"
val="${val%%+( )}"
echo "|${val}|"