删除文件名的一部分(不包括字符串)



我有一个脚本,是非常友好地为我提供了一段时间前,它允许我生成输入文件插入坐标从一系列。xyz文件到模板文件(创建新文件通过复制坐标文件的内容到模板文件)。

我试着改编这个剧本,做一些非常相似的事情,但在一个非常轻微的不同,但令人讨厌的方式。在脚本中,为存放这些新文件而创建的新目录命名如下:

# File name is in the form '....Hnnn.xyz';
# this will parse nnn from that name.
local inputNumber=$coordFile
# Remove '.xyz'.
inputNumber=${inputNumber%.xyz}
# Remove everything up to and including the 'H'.
inputNumber=${inputNumber##*H}
# Subdirectory name is based on the input number.
local outDir=$baseDir/D$inputNumber
# Create the directory if it doesn't exist.
if [[ ! -d $outDir ]]; then
mkdir $outDir
fi

这对我的上一个问题有效,因为文件都以xxxx_DH000.xyz的形式命名。但是,现在我使用xxxx.000.xyz的形式来命名文件。虽然脚本中的其他一切都可以工作,但我不知道如何以000的形式命名新目录。

脚本中我认为需要稍微编辑的行是它说inputNumber=${inputNumber##*H}的地方。我不能弄清楚的是如何让脚本删除的一切,但不是包括一个0。我在网上搜索过,但我发现的唯一问题/答案与通过剥离部分原始名称来重命名文件有关,涉及删除所有"不超过"并包括"字符串"。

我能够用inputNumber=${inputNumber##*0}生成名为1、2、3等的目录,但是我希望所有三个数字都存在(即我想创建目录001、002、003等)。

顺便说一句,我不能使用.作为截止点,因为每个文件名中都有多个.。其中一个文件名的示例是tma.h2s-2-pes-b97m-d4-tz.011.xyz

是否有一些方法可以让脚本简单地根据完整的三位数命名文件?

虽然在这种情况下不需要,但zsh确实支持删除字符串中匹配模式之前的文本。这些参数展开将删除字符串中第一个0之前的所有内容,但保留0:

inputNumber='tma.h2s-2-pes-b97m-d4-tz.011.xyz'
inputNumber=${inputNumber:r} # remove '.xyz'
inputNumber=${(SM)inputNumber##0*}
print ${inputNumber}
# ==> 011

这包括一些zsh-isms:

  • ${...:r}返回文件名的'根',删除扩展名。
  • (S)-参数扩展标志,用于改变##扩展的行为。它现在将在字符串的中间搜索模式,而不仅仅是在开头。
  • (M)-在结果中包含模式匹配(0*)的标志。

这取决于总是以0开头的数字,这可能不是一个好的选择-099之后是什么文件?


下一个版本使用zsh扩展的glob模式来查找两个周期之间的数字,并返回该数字-即它将在.11.,.011..2345.中找到该数字,但不在.x11.中:

coordFile='tma.h2s-2-pes-b97m-d4-tz.022.xyz'
inputNumber=${(*)coordFile//(#b)*.(<->).*/${match}}
print ${inputNumber}
# ==> 022

部分段落:

  • ${...//.../...}-替代扩展。
  • (*)-启用此扩展的extendedglob
  • (#b)- globbing标志启用'反向引用',使$match将工作。
  • <->-匹配一个数字。如果需要,可以限制在一个范围内,如<100-199>
  • (<->)-将号码放入匹配组
  • *..*-数字前后的所有内容;
  • ${match}-从模式的括号部分匹配的字符串。它被用作整个字符串的替换,所以我们只得到数字。如果输入字符串的多个部分与模式匹配,这将是最后一个。match实际上是一个数组,但由于模式中只有一个匹配组,因此不需要使用${match[1]}进行索引。

这个变体使用标准正则表达式来查找数字:

coordFile='tma.h2s-2-pes-b97m-d4-tz.033.xyz'
match=
[[ $coordFile =~ .*\.([[:digit:]]+)\..* ]]
inputNumber=${match[1]}
print ${inputNumber}
# ==> 033

[[ ]]测试之后,match数组将包含正则表达式中任何括号组的匹配-在这里,这将是两个句号/句号之间的一组或多个数字。


但是,正如@choroba和Fravadona所指出的,由于数字将始终位于字符串的末尾,您可以使用标准的#/##/%/%%扩展来删除仅基于.s的字符串的部分。这是一种常见的习惯用法,对于许多shell程序员来说都很熟悉,并且也可以在bash中工作(注意,原始脚本的其他部分依赖于zsh)。

inputNumber='tma.h2s-2-pes-b97m-d4-tz.044.xyz'
inputNumber=${inputNumber%.xyz}
inputNumber=${inputNumber##*.}
print ${inputNumber}
# ==> 044

zsh中,所有内容都可以合并为一个嵌套的替换:

baseDir='files/are/here'
coordFile='tma.h2s-2-pes-b97m-d4-tz.055.xyz'
local outDir=$baseDir/D${${coordFile:r}##*.}
print $outDir
# ==> files/are/here/D055

最新更新