shell中提取文件名或目录名

本文介绍了在Linux环境下使用变量替换和特定命令来提取文件名、目录名和文件后缀的方法。通过详细解析${var##*/}

很多时候在使用Linux的shell时,我们都需要对文件名或目录名进行处理,通常的操作是由路径中提取出文件名,从路径中提取出目录名,提取文件后缀名等等。例如,从路径/dir1/dir2/file.txt中提取也文件名file.txt,提取出目录/dir1/dir2,提取出文件后缀txt等。

下面介绍两种常用的方法来进行相关的操作。

一、使用 1 、 {} 1、 1{var##*/}
该命令的作用是去掉变量var从左边算起的最后一个’/‘字符及其左边的内容,返回从左边算起的最后一个’/’(不含该字符)的右边的内容。使用例子及结果如下:

从运行结果可以看到,使用该命令,可以提取出我们需要的文件名file.txt。

若使用时在shell程序文件中,可以使用变量来保存这个结果,再加以利用,如file=${var##*/}

2、${var##*.}
该命令的作用是去掉变量var从左边算起的最后一个’.‘字符及其左边的内容,返回从左边算起的最后一个’.’(不含该字符)的右边的内容。使用例子及结果如下:

从运行结果可以看到,使用该命令,可以提取出我们需要的文件后缀。

如果文件的后缀不仅有一个,例如,file.tar.gz,命令KaTeX parse error: Expected '}', got '#' at position 5: {var#̲#*.}仅能提取最后一个后缀,…{var#*.}命令了。

3、${var#*.}
该命令的作用是去掉变量var从左边算起的第一个’.‘字符及其左边的内容,返回从左边算起第一个’.’(不含该字符)的右边部分的内容。使用例子及结果如下:

从运行结果可以看到,使用该命令,可以提取出文件的多个后缀。

4、${var%/*}
该命令的使用是去掉变量var从右边算起的第一个’/‘字符及其右边的内容,返回从右边算起的第一个’/’(不含该字符)的左边的内容。使用例子及结果如下:

从运行的结果可以看到,使用该命令,可以提取出我们需要的文件所在的目录

5、${var%%.*}
该命令的使用是去掉变量var从右边算起的最后一个’.‘字符及其右边的内容,返回从右边算起的最后一个’.’(不含该字符)的左边的内容。使用例子及结果如下:

当我们需要建立一个与文件名相同名字(没有后缀)的目录与对应的文件相对应时,就可以使用该命令来进行操作。例如,解压文件的情况就与此类似,我们压缩文件file.zip时,会在与file.zip同级目录下建立一个名为file的目录。

6、 总 结 其 实 {}总结 其实 {}并不是专门为提取文件名或目录名的,它的使用是变量的提取和替换等等操作,它可以提取非常多的内容,并不一定是上面五个例子中的’/‘或’.’。也就是说,上面的使用方法只是它使用的一个特例。

看到上面的这些命令,可能会让人感到非常难以理解和记忆,其实不然,它们都是有规律的。
#:表示从左边算起第一个
%:表示从右边算起第一个
##:表示从左边算起最后一个
%%:表示从右边算起最后一个
换句话来说,#总是表示左边算起,%总是表示右边算起。

*:表示要删除的内容,对于#和##的情况,它位于指定的字符(例子中的’/‘和’.’)的左边,表于删除指定字符及其左边的内容;对于%和%%的情况,它位于指定的字符(例子中的’/‘和’.’)的右边,表示删除指定字符及其右边的内容。这里的’'的位置不能互换,即不能把号放在#或##的右边,反之亦然。

例如:${var%%x*}表示找出从右边算起最后一个字符x,并删除字符x及其右边的字符。

看到这里,就可以知道,其实该命令的用途非常广泛,上面只是指针文件名和目录名的命名特性来进行提取的一些特例而已。

二、basename和dirname
${}并不是专门为提取文件名和目录名设计的命令,那么basename和dirname命令就是专门为做这一件事而已准备的了。

1、basename

该命令的作用是从路径中提取出文件名,使用方法为basename NAME [SUFFIX]。

1)从路径中提出出文件名(带后缀),例子如下:

2)从上面命令的用法中可以看到,后缀(SUFFIX)是一个可选项。所以,若只想提取出文件名file,而不带有后缀,还可以在变量的后面加上后缀名,例子如下:

2、dirname
该命令的作用是从路径中提取出目录名,使用方法为 dirname NAME
使用例子如下:

这样就提取出了file.txt文件所在的目录。

注:该命令不仅能提取出普通文件所的目录,它能提取出任何文件所在的目录,例如目录所在的目录,如下:

它提取出了目录dir2所在的目录dir1.
https://www.jb51.net/article/101569.htm

<think>嗯,用户需要了解在shell脚本中提取文件名的方法。用户之前的问题是关于shell脚本提取文件名的方法,并且提供了三个引用资料,这些资料展示了不同的方法。 用户可能是在编写shell脚本时需要处理文件路径,比如批量重命名处理日志文件。用户引用的资料中提到了几种方法:使用basename命令、使用参数扩展(如${var##*/})以及提取文件名和扩展名的技巧。用户的需求很明确,就是汇总这些方法。 首先,basename命令是直接获取路径中的文件名部分。例如,basename /path/to/file.txt会输出file.txt。这是一种标准方法,适合需要简单获取文件名的情况。 其次是参数扩展,这是shell内置的功能,效率高。比如${path##*/}会从路径中删除直到最后一个斜杠之前的内容,留下文件名。这种方法不需要调用外部命令,执行速度快,适合在循环中处理大量文件时使用。 另外,用户引用资料中还提到了如何分离文件名和扩展名,比如${filename%.*}获取不带扩展名的文件名,${filename##*.}获取扩展名。这些技巧在实际脚本中很实用,比如修改文件扩展名时。 用户可能还需要知道如何处理特殊情况,比如路径以斜杠结尾文件名包含空格。basename命令在路径以斜杠结尾时会返回空,而参数扩展${path##*/}在这种情况下会正确返回文件名。对于包含空格的文件名,确保变量用双引号包裹,如"$file",避免单词拆分错误。 最后,用户可能想了解哪种方法更高效。参数扩展由于是shell内置,通常比调用外部命令basename更快,尤其在处理大量文件时。但basename更易读,适合脚本可读性要求高的场景。 需要确保回答覆盖所有主要方法,并说明它们的优缺点,帮助用户根据实际情况选择合适的方法。同时提醒用户注意文件名中的特殊字符和空格问题,避免常见错误。</think>在 Shell 脚本中提取文件名有多种方法,主要分为使用 **`basename` 命令**和 **Shell 参数扩展**两种方式: ### 🛠 方法 1:使用 `basename` 命令 `basename` 命令专门用于从路径中剥离目录,返回文件名部分(包含扩展名)。 ```bash #!/bin/bash # 示例文件路径 file_path="/home/user/docs/report.txt" # 提取完整文件名 (report.txt) filename=$(basename "$file_path") echo "完整文件名: $filename" # 输出: report.txt # 提取不带扩展名的文件名 (report) filename_no_ext=$(basename "$file_path" .txt) echo "无扩展名文件名: $filename_no_ext" # 输出: report # 者动态去除任意扩展名 filename_no_ext=$(basename "$file_path" .${file_path##*.}) echo "无扩展名文件名(动态): $filename_no_ext" # 输出: report ``` **说明:** * `basename "路径"` 返回完整文件名。 * `basename "路径" ".扩展名"` 返回去除指定扩展名的文件名。 * 处理包含空格特殊字符的路径时,**务必使用双引号**包裹变量(如 `"$file_path"`)。 ### ⚡ 方法 2:使用 Shell 参数扩展 Shell 内置的字符串操作功能强大且高效,无需调用外部命令。 ```bash #!/bin/bash # 示例文件路径 file_path="/var/log/apache/access.log.gz" # 提取完整文件名 (access.log.gz) full_filename="${file_path##*/}" echo "完整文件名: $full_filename" # 输出: access.log.gz # 提取不带扩展名的文件名 (access.log) # 方法:删除最后一个 '.' 及其右侧的所有字符 filename_no_ext="${full_filename%.*}" echo "无扩展名文件名(一级): $filename_no_ext" # 输出: access.log # 提取最基础的文件名 (去除所有扩展名, access) # 方法:删除第一个 '.' 及其右侧的所有字符 base_name="${full_filename%%.*}" echo "最基础文件名: $base_name" # 输出: access # 提取最后一个扩展名 (gz) extension="${full_filename##*.}" echo "扩展名: $extension" # 输出: gz ``` **参数扩展说明:** * `${var##*/}`:从变量 `$var` 开头删除**最长匹配** `*/` 模式的子串(即删除所有目录部分),留下文件名。 * `${var%.*}`:从变量 `$var` 末尾删除**最短匹配** `.*` 模式的子串(即删除最后一个点及其后的扩展名)。 * `${var%%.*}`:从变量 `$var` 末尾删除**最长匹配** `.*` 模式的子串(即删除第一个点及其后的所有扩展名)。 * `${var##*.}`:从变量 `$var` 开头删除**最长匹配** `*.` 模式的子串(即删除直到最后一个点之前的所有内容),留下最后一个扩展名。 ### 📌 总结与选择 * **`basename`:** 语法清晰,用途明确,是 POSIX 标准命令,适合需要兼容不同 Shell 脚本可读性优先的场景。提取文件名去除特定扩展名时很方便[^3]。 * **参数扩展:** 纯 Shell 内置操作,执行效率更高(尤其处理大量文件时)。功能更灵活(可提取基础名、多级扩展名等),适合对性能要求高需要复杂字符串处理的脚本[^2]。 **关键区别示例:** ```bash path="dir/subdir/file.tar.gz" # basename basename "$path" # 输出: file.tar.gz basename "$path" .gz # 输出: file.tar basename "$path" .tar.gz # 输出: file (注意:必须完全匹配后缀) # 参数扩展 filename="${path##*/}" # 输出: file.tar.gz no_ext="${filename%.*}" # 输出: file.tar (仅去除.gz) base="${filename%%.*}" # 输出: file (去除所有后缀) ext="${filename##*.}" # 输出: gz (获取最后一级扩展名) ``` 选择哪种方法取决于你的具体需求(是否需要兼容性、是否需要处理多级扩展名)和个人偏好。两者都是 Shell 脚本中处理文件名的标准做法。 --- ### 🔍 相关问题 1. **如何在 Shell 脚本中批量提取目录下所有文件的文件名并保存到列表?** > 可以使用 `for` 循环结合 `basename` 参数扩展处理 `find` `ls` 的输出。 ```bash # 示例:提取当前目录所有 .txt 文件的文件名(不含路径) for file in *.txt; do name=$(basename "$file") # name="${file##*/}" echo "$name" >> filelist.txt done ``` 2. **Shell 脚本中如何安全处理包含空格特殊字符的文件名?** > **务必用双引号包裹变量引用**(如 `"$file"`),使用 `find -print0` 和 `xargs -0` 处理文件列表,避免单词拆分错误。 3. **如何仅获取文件所在的目录路径(不含文件名)?** > 使用 `dirname` 命令:`dir_path=$(dirname "/path/to/file.txt")` 参数扩展:`dir_path="${full_path%/*}"`。 4. **Shell 参数扩展 `${var%%.*}` 和 `${var%.*}` 在处理 `file.name.with.dots.txt` 时结果有何不同?** > `${var%%.*}` 输出 `file`(删除第一个点之后所有内容),`${var%.*}` 输出 `file.name.with.dots`(仅删除最后一个点之后的内容)。 [^1]: 引用示例展示了使用 `%%` 和 `##` 进行字符串截取的基本思路。 [^2]: 引用详细说明了使用 `${var%}` 和 `${var#}` 系列操作符提取文件名各部分的方法。 [^3]: 引用介绍了 `basename` 命令的标准用法,用于从路径中提取文件名
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值