龙空技术网

关于参数扩展、子字符串提取和获取文件扩展名的优化建议

SuperOps 97

前言:

当前你们对“java文件后缀名获取”大概比较注意,我们都需要分析一些“java文件后缀名获取”的相关资讯。那么小编同时在网络上搜集了一些关于“java文件后缀名获取””的相关知识,希望朋友们能喜欢,姐妹们快快来学习一下吧!

如何使用参数扩展?如何获取子字符串?如何获取没有扩展名的文件,或者只获取文件的扩展名?有哪些好的方法可以做到basename和dirname?

参数扩展是一个重要的主题,涉及将变量或特殊参数替换为其对应的值。在类似Bash的Bourne shell中,参数扩展是解引用(引用)变量的主要方式之一,并且还提供了方便的值操作功能。请记住,在进行扩展时要给定适当的引号。

首先,我们来看一组从参数开头或末尾删除子字符串的功能示例。下面是一个使用参数扩展实现类似主机名(由点分隔的组件)的示例:

parameter     result-----------   ------------------------------$name         polish.ostrich.racing.champion${name#*.}           ostrich.racing.champion${name##*.}                         champion${name%%.*}   polish${name%.*}    polish.ostrich.racing

此外,接下来我们以典型文件名为例展示参数扩展的使用:

parameter     result-----------   --------------------------------------------------------$file         /usr/share/java-1.4.2-sun/demo/applets/Clock/Clock.class${file#*/}     usr/share/java-1.4.2-sun/demo/applets/Clock/Clock.class${file##*/}                                                Clock.class${file%%/*}${file%/*}    /usr/share/java-1.4.2-sun/demo/applets/Clock

需要注意的是,参数扩展不支持嵌套。如果需要进行多个扩展步骤,请使用一个变量来保存第一个扩展结果:

# foo holds: key="some value"bar=${foo#*=\"} bar=${bar%\"*}# now bar holds: some value

下面是一些更多示例

${string:2:1}   # 字符串 string 的第三个字符(0、1、2 表示第三个字符)${string:1}     # 从字符串 string 的第二个字符开始的子串                # 注意:这等价于 ${string#?}${string%?}     # 删除字符串 string 的最后一个字符后的子串${string: -1}   # 字符串 string 的最后一个字符${string:(-1)}  # 字符串 string 的最后一个字符,备选语法                # 注意:string:-1 表示另一种完全不同的含义;见下文。${file%.mp3}    # 去掉文件名中的 .mp3 扩展名                # 在循环中非常有用,例如:for file in *.mp3; do ...${file%.*}      # 去掉文件名中的最后一个扩展名${file%%.*}     # 去掉文件名中的所有扩展名${file##*.}     # 只保留文件名中的扩展名,假设存在一个扩展名。如果不存在,则会展开为:$file
文件名操作示例

这里是一种符合POSIX标准的方式,可以提取完整路径名中的目录组件、文件名、仅扩展名、没有扩展名的文件名("stub"),在"stub"末尾出现的任何数值部分(忽略文件名中间的数字),对该数字进行算术操作(例如递增一),并重新组装整个文件名,在文件名前添加前缀,并用另一个数字替换文件名中的数字。

FullPath=/path/to/name4afile-009.ext     # result:   #   /path/to/name4afile-009.extFilename=${FullPath##*/}                             #   name4afile-009.extPathPref=${FullPath%"$Filename"}                     #   /path/to/FileStub=${Filename%.*}                              #   name4afile-009FileExt=${Filename#"$FileStub"}                      #   .extFnumPossLeading0s=${FileStub##*[![:digit:]]}         #   009FnumOnlyLeading0s=${FnumPossLeading0s%%[!0]*}        #   00FileNumber=${FnumPossLeading0s#"$FnumOnlyLeading0s"} #   9NextNumber=$(( FileNumber + 1 ))                     #   10NextNumberWithLeading0s=$(printf "%0${#FnumPossLeading0s}d" "$NextNumber")                                                     #   010FileStubNoNum=${FileStub%"$FnumPossLeading0s"}       #   name4afile-NewFullPath=${PathPref}New_${FileStubNoNum}${NextNumberWithLeading0s}${FileExt}                        # Final result is:           #   /path/to/New_name4afile-010.ext

请注意,如果 $FullPath 是 SomeFilename.ext 或其他不带斜线的路径名,则尝试使用 PathPref="${FullPath%/*}" 获取路径名中的目录组件时,将无法返回空字符串。同样,使用 FileExt="${Filename#*.}​"获取文件扩展名时,如果 $Filename​ 没有点(因此也没有扩展名),也会返回空字符串。

还要注意的是,为了进行算术运算,必须去掉 $FileNumber​ 的前导零,否则数字将被解释为八进制。另外,也可以添加 10# 前缀,强制以 10 为底。在上面的例子中,尝试计算 $(( FnumPossLeading0s + 1 )) ​结果会出错,因为 "00809 "不是一个有效的数字。如果我们使用 "00777",就不会出错,但 $(( FnumPossLeading0s + 1 )) ​的结果将是 "1000"(因为八进制 777 + 1 是八进制 1000),这可能不是我们想要的结果。

在变量赋值中不需要加引号,因为 WordSplitting 不会发生。另一方面,在参数扩展中引用的变量需要加引号(例如,在PathPref=${FullPath%"$Filename"}​中引用 $Filename​ ),否则文件名中的任何 * 或 ? 或其他此类字符都会错误地成为参数扩展的一部分(例如,如果星号是文件名中的第一个字符 ,则可以尝试 FullPath="dir/*filename" ​)。

数组上的参数扩展

BASH 数组非常灵活,因为它们与其他 shell 扩展很好地结合在一起。任何可以在标量或单个数组元素上执行的参数扩展,都可以同样适用于整个数组或位置参数集,这样所有成员都会一次性扩展,可能还会在每个元素上映射额外的操作。这可以通过扩展 @、、arrayname[@] 和 arrayname[] 形式的参数来实现。这些特殊扩展参数必须正确加引号--几乎总是双引号(如"{cmd[@]}")--这样,无论其内容如何,成员都会按字面意思作为单个单词处理。例如,arr=("${list[@]}" foo) 可以正确处理 list 数组中的所有元素。

首先是扩展:

$ a=(alpha beta gamma)  # 通过复合赋值将值分配给基本数组$ echo "${a[@]#a}"      # 去掉每个元素开头的 'a'lpha beta gamma$ echo "${a[@]%a}"      # 去掉每个元素结尾的 'a'alph bet gamm$ echo "${a[@]//a/f}"   # 字符串替换,将每个元素中的 'a' 替换为 'f'flphf betf gfmmf

以下扩展(在开头或结尾处替换)对下一部分非常有用:

$ echo "${a[@]/#a/f}"   # substitute a for f at startflpha beta gamma$ echo "${a[@]/%a/f}"   # at endalphf betf gammf

我们使用它们来为列表中的每个成员添加前缀或后缀:

$ echo "${a[@]/#/a}"    # 在每个元素的开头附加字符 'a'aalpha abeta agamma     #    (感谢 floyd-n-milan 提供此注释)$ echo "${a[@]/%/a}"    # 在每个元素的结尾附加字符 'a'alphaa betaa gammaa

它的工作原理是用我们希望附加的值代替开头或结尾的空字符串。

最后,举例说明如何在脚本中使用此功能,比如为每个目标添加用户自定义的前缀:

$ PFX=inc_$ a=("${a[@]/#/$PFX}")$ echo "${a[@]}"inc_alpha inc_beta inc_gamma

如你所想,这非常有用,因为它可以省去对数组中每个成员的循环。

特殊参数 @ 也可以用作数组,用于参数扩展:

${@:(-2):1}             # 第二个到最后${@: -2:1}              # 另一种可选择的语法

但不能使用 ${@:-2:1}(注意空格),因为这与下一节描述的语法相冲突。

可移植性

最初的 Bourne shell(第 7 版 Unix)只支持非常有限的参数扩展选项:

${var-word}             # 如果 var 已定义,则使用 var;否则使用 "word"${var+word}             # 如果 var 已定义,则使用 "word";否则什么都不做${var=word}             # 如果 var 已定义,则使用 var;否则使用 "word" 并且...                        #   还要将 "word" 分配给 var${var?error}            # 如果 var 已定义,则使用 var;否则输出 "error" 并退出

这些是唯一完全可移植的扩展。

POSIX shells(以及 KornShell 和 BASH)提供了这些扩展,另外还有一个小变种:

${var:-word}             # 如果 var 已定义并且不为空,则使用 var;否则使用 "word"类似地,${var:+word} 等也是类似的用法。

POSIX、Korn(所有版本)和 Bash 均支持 ${var#word}​、${var%word}​、${var##word}​ 和 ${var%%word} ​扩展。

ksh88 不支持 ${var/replace/with} ​或 ${var//replace/all}​,但 ksh93 和 Bash 支持。

ksh88 不支持数组的花式扩展(例如,${a[@]%.gif}​),但 ksh93 和 Bash 支持。

ksh88 不支持 arr=(...) 类型的复合赋值。要么使用 set -A arrayname -- elem1 elem2​ ...,要么使用 arr[0]=val1 arr[1]=val2​ ...为每个元素单独赋值。

学习更多shell最佳实践

如果您觉得文章内容对你有一点帮助可以关注我,我在头条平台会持续分享更多实用的shell技巧和最佳实践,如果想系统的快速学习shell的各种高阶用法和生产环境避坑指南可以看看《shell脚本编程最佳实践》专栏,专栏里有更多的实用小技巧和脚本代码分享。

标签: #java文件后缀名获取