【问题标题】:Shell parameter expansion working in ksh but not in bashShell 参数扩展在 ksh 中有效,但在 bash 中无效
【发布时间】:2019-10-08 10:40:12
【问题描述】:

为什么下面的代码在 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##*/}

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

【问题讨论】:

  • 你的 bash 版本是什么?我在我的 bash 5.0.11 the folder name after the last slash 上得到了正确的输出 - 使用 basename 是最便携的。最后一个斜杠之前的部分使用dirname
  • 我得到了一行 bash (4.4.20)、zsh 和 dash。两行 ksh93。

标签: bash shell parameters ksh expansion


【解决方案1】:

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

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

产量:

folderA/folderB/
folderC

相关链接:Bash Reference Manual § Pattern Matching.


顺便说一句,您实际上并不需要扩展 glob。

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

以上脚本同样适用于任何符合 POSIX 标准的 shell。

【讨论】:

    【解决方案2】:

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

    folderA/folderB/folderC
    

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

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

    请参阅 the other answer,了解 GNU bash 如何需要 shopt -s extglob 以另外支持与 Korn shell 兼容的扩展通配模式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-06
      • 1970-01-01
      • 2021-11-01
      • 2021-08-23
      • 1970-01-01
      相关资源
      最近更新 更多