Shell处理文件路径


文件路径

Shell处理文本路径

编写Shell脚本的过程中,经常会和文件名和文件路径打交道。如果用户输入了一个文件的全名(可能包含绝对路径和文件后缀),如何得到文件的路径名,文件名,文件后缀这些信息呢?

本文就介绍了如何获得文件路径名、文件名、文件后缀等等信息。

获取文件名与目录名:basename与dirname

Shell中提供了basenamedirname两个命令来获得文件的名字(不是文件的路径)文件的目录名

fullfile=/the/path/foo.txt
echo $fullfile

fullname=$(basename $fullfile)
echo $fullname

dir=$(dirname $fullfile)
echo $dir

运行结果为:

basename和dirname获取文件名与目录名

单后缀文件stem与suffix:cut

我们上面通过basename获得的文件名是文件的完整名字,包含后缀名在内。但是有的时候我们可能只想要这个文件名不包含后缀的部分。因此,这里先讲解如何切分只有一个后缀名的文件的后缀和不含后缀的名字。

事实上,basename最后获得的文件名其实就是一个字符串,所以针对只有一个后缀名的后缀,直接用cut命令从.出切分即可。

fullfile=/the/path/foo.txt
echo $fullfile

fullname=$(basename $fullfile)
echo $fullname

stem=$(echo $fullname | cut -d . -f1)
suffix=$(echo $fullname | cut -d . -f2)
echo $stem
echo $suffix

运行结果为:

cut切分单后缀文件名

多后缀文件stem与suffix:sed

有时候文件可能不止有一个后缀,比如*.tar.gz,此时该怎么得到文件的名字、全部后缀,或者最后一个后缀呢?再cut一回?当然可以,但是如果文件名是mylib.1.0.1a.zip这样的呢?

因为文件名本身就是字符串所以这个时候,就需要更加强大的文本处理工具。而说到文本处理工具,那就是sed了,所以就利用sed和正则表达式,通过掐头去尾留下我们想要的部分来实现获取各种名字。

fullname=mylib.1.0.1a.zip

last_suffix=$(echo $fullname | sed 's/\.[^.]*$//')
name=$(echo $fullname | sed 's/^.*\.//')

echo $fullname, $last_suffix, $name

运行结果为:

sed切分多后缀文件名

这里面的两个正则表达式逻辑是这样的:

  • 文件名:把以.字符开头以后一直到行尾都是非.字符的子串替换为空。
  • 后缀名:把从行首开始以.字符结尾的子串替换为空。

光用语言把这两个正则表达式描述出来脑细胞也要死不少。有没有像上面cut版本一样简单容易理解的方法呢?由于.分隔符的个数不确定,正常使用cut来分割最后一个.字符是不太可能的。但是我们可使用 rev 命令将字符串反转一下,区分后缀和文件名的.字符位置就确定了。截取了想要的部分之后,再次反转就得到了我们想要的内容。

fullname=mylib.1.0.1a.zip

stem=$(rev <<< $fullname | cut -d . -f2- | rev)
suffix=$(rev <<< $fullname | cut -d . -f1 | rev)
echo $stem, $suffix

运行结果为:

rev获取最后一个后缀

使用Bash扩展

1. Bash扩展介绍

在前面介绍Bash特性的文章中,我们介绍Bash中有很多的扩展。实际上,针对文本路径,Bash也提供了非常多的扩展。Bash扩展类似于预定义宏,我们直接用就行了,Bash解释器会帮助我们处理扩展。

看下面的例子:

fullfile=/the/path/mylib.1.0.1a.zip

dir="${fullfile%/*}"
fullname="${fullfile##*/}"
stem="${fullname%.*}"
extension="${fullname##*.}"

echo $dir
echo $fullname
echo $stem
echo $extension

运行后的结果:

Bash扩展运行结果

使用Bash扩展来获得文件名、文件目录什么的,真是不能再简洁了。大括号之内变量名配合几个神奇的字符,就是Shell的参数扩展(Parameter Extension)功能

  • ${fullfile##*/}:从前面开始删除fullfile中最大匹配(longest matching pattern) */ 的字符串
  • ${fullfile%/*}:从后面开始删除fullfile中最小匹配(shortest matching pattern) /* 的字符串
  • ${fullname##*.}:从前面开始删除fullname中最大匹配(longest matching pattern) *. 的字符串
  • ${fullname%.*}:从后面开始删除fullname中最小匹配(shortest matching pattern) .* 的字符串

参数扩展有多种形式,在shell编程中可以用作参数的拼接,字符串的替换,参数列表截取,变量初值等操作,这里不再详述,请参考后面的功能列表和官方文档

2. 参数扩展功能列表

参数形式 扩展后
x{y,z} xy xz,这里xyz都是字符
${x}{y, z} ${x}y ${x}z,这里x是一个变量
${x}{y, $z} ${x}y ${x}${z},这里xz都是变量
${param#pattern} param前面删除pattern的最小匹配
${param##pattern} param前面删除pattern的最大匹配
${param%pattern} param后面删除pattern的最小匹配
${param%%pattern} param后面删除pattern的最大匹配
${param/pattern/string} param中用string替换pattern的第一次匹配,string可为空
${param//pattern/string} param中用string替换pattern的所有匹配,string可为空
${param:3:2} 截取$param中索引3开始的2个字符
${param:3} 截取$param中索引3至末尾的字符
${@:3:2} 截取参数列表$@中第3个开始的2个参数
${param:-word} $param为空或未设置,则参数式返回word$param不变
${param:+word} $param为非空,则参数式返回word$param不变
${param:=word} $param为空或未设置,则参数式返回word,同时$param设置为word
${param:?message} $param为空或未设置,则输出错误信息message,若包含空白符,则需引号

文章作者: Jack Wang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Jack Wang !
 上一篇
计算机开机那点事:从按下电源键到操作系统 计算机开机那点事:从按下电源键到操作系统
本文是JackOS开发笔记之Linux开机那点事系列中的一篇,讲解了计算开机时从按下电源键到运行操作系统期间发生的事
下一篇 
CPU访问内存:内存分段与内存分页 CPU访问内存:内存分段与内存分页
本文介绍了CPU访问内存的两种方式:内存分段式访问与内存分页式访问。此外还讲解了包括物理地址、逻辑地址、有效地址和虚拟地址等等在内的概念
2022-11-15
  目录