Bash 参数扩展 - 获取文件的直接父目录

Bash Parameter Expansion - get immediate parent directory of file

我想获取给定文件的直接父目录的名称,例如foo 给定 /home/blah/foo/bar.txt,使用参数扩展。现在我可以用两行来完成:

f="/home/blah/foo/bar.txt"
dir_name="${f%/*}"
immediate_parent="${dir_name##*/}"

但我对参数扩展还很陌生,所以我认为这可以优化。有没有办法只在一行中完成?

你不能用单个参数展开,但你可以使用=~,Bash的正则表达式匹配运算符:

[[ $f =~ ^.*/(.+)/.+$ ]] && immediate_parent=${BASH_REMATCH[1]}

注意:假定绝对路径至少包含 2 个组件。

如果可以接受调用外部实用程序,awk 提供了一个可能更简单的替代方法:

immediate_parent=$(awk -F/ '{ print $(NF-1) }' <<<"$f")

至于为什么不能用单参数展开:

  • 参数扩展允许剥离 或者 前缀 (# / ## ) 一个后缀 (% / %%) 来自变量值,但不是两者.

    • 嵌套 前缀和后缀修剪扩展虽然原则上受支持,但无济于事,因为您需要迭代 修改的值,而扩展只会 returns 修改后的字符串;换句话说:有效的 overall 扩展仍然只执行 single 扩展操作,你再次陷入 either一个前缀一个后缀操作。
  • 使用单个参数扩展,提取一个内部子串只能通过字符位置和长度;例如,基于示例输入的硬编码解决方案将是:immediate_parent=${f:11:3}

    • 可以 使用算术表达式甚至命令替换作为参数扩展参数,但这种方法的毫无意义 - 至少在这种情况下 - 变得很明显,如果我们试试;注意嵌入式命令替换 - 第一个计算字符位置,第二个计算长度:

      immediate_parent=${f:$(d=${f%/*/*}; printf %s ${#d})+1:$(awk -F/ '{ print length($(NF-1)) }' <<<"$f")}