如何从 shell 变量获取路径的文件名部分

如何从 shell 变量获取路径的文件名部分

shell 变量保存一个路径。如何获取其文件名部分?

在bash(1)中,我进行了实验,发现可以通过."${i/*\///}"where iis环境变量的名称来完成。这样的方法不仅丑陋,而且在路径不包含任何/字符的情况下也是错误的。

我将演示一个需要此类功能的实际案例。假设我们要为源目录中的每个 PDF 文件创建一个到当前目录的符号链接。

$ for i in /source/path/*.pdf; do\
  ln -s "$i" ."${i/*\///}"; \
  done

答案1

${i##*/}

这适用于 Posix shell,包括bashdashkshzsh等。来自标准POSIX 参数扩展部分Posix Shell & Utilities 规范:

${参数##[字]}
删除最大前缀模式。该词应扩展以产生一种模式。然后,参数扩展应产生参数,其中前缀的最大部分与删除的模式匹配。

或者,传统上,该basename命令已用于此目的。 警告:性能可能成为一个重要问题,因为basename它是作为外部命令实现的(例如,/usr/bin/basename)。因为您是在循环内执行此操作,所以您将为每个文件调用一个外部命令。对于 1000 个文件的列表,这可能是 0.05 秒(参数扩展)和 2.0 秒(basename命令)之间的差异。但对于包含 10,000 个文件的列表,这可能是 0.5 秒(扩展)与 20 秒 ( ) 之间的差异basename。随着文件数量的增加,性能差异变得更加极端。

为了可读性和性能,您可以实现自己的basename函数,例如:

mybasename() { echo "${1##*/}"; }

(为函数选择更好的名称和/或完整basename命令行界面的实现留给读者作为练习。:)

答案2

您可以将路径放入变量中,并使用其长度计数从完整路径名中仅获取所需的子字符串,如下所示:

$ pth="/source/path/";
$ for i in $path*.pdf; do \
  ln -s "$i" ./"${i:${#pth}}"; \
  done

相关内容