Shell 参数扩展在 ksh 中有效但在 bash 中无效

Shell parameter expansion working in ksh but not in bash

为什么以下代码在 ksh 和 bash

中产生不同的输出
p="folderA/folderB/folderC"
echo ${p%%+([^/])}
echo ${p#${p%%+([^/])}}

ksh 输出:

folderA/folderB/
folderC

bash 输出:

folderA/folderB/folderC

我特别困惑,因为我使用 bash documentation 创建了这个参数扩展。

我想提取最后一个斜杠后的文件夹名称。我找到了另一种在 ksh 和 bash:

中工作的方法
echo ${p##*/}

但我想了解为什么第一种方法不起作用。

+(...) 是扩展的 glob 语法,您需要启用 extglob 特性才能让 bash 理解它。并且如 中所述,通常不应使用抑扬符来否定字符 class。 Bash 容忍这个错误,但无论如何为了可移植性让我们使用正确的语法:

shopt -s extglob
p="folderA/folderB/folderC"
echo "${p%%+([!/])}"
echo "${p#${p%%+([!/])}}"

产量:

folderA/folderB/
folderC

相关link:Bash Reference Manual § Pattern Matching


顺便说一句,你真的不需要为此扩展 glob。

p="folderA/folderB/folderC"
echo "${p%${p##*/}}"
echo "${p##*/}"

以上脚本在任何符合 POSIX 的 shell.

上同样有效

另一个更符合标准的 Korn shell 实际上输出

folderA/folderB/folderC

后跟一个空行。这是因为 shell glob 是 不是 正则表达式,字符 class 协商运算符是一个假朋友。

在POSIX shell中,[^/] is actually unspecified但通常(["^"/]更清楚)表示“^/”,但你会想要“任何不是 / 的东西”,在 POSIX shell glob 中,它是 [!/]

有关 GNU bash 如何需要 shopt -s extglob 支持 Korn shell 兼容的扩展 globbing 模式的解释,请参阅