我有一堆文件需要在 Linux 机器上处理。这些文件看起来像这样:
2009-08-18T034353_DR1_4N-NAC_123456_1234_band1.ntf
2009-08-18T034353_DR1_4N-NAC_123456_1234_browse.jpg
2009-08-18T034353_DR1_4N-NAC_123456_1234_band2.ntf
2009-08-18T034353_DR1_4N-NAC_123456_1234_license.txt
2009-08-18T034353_DR1_4N-NAC_123456_1234_metadata.xml
2009-08-18T034353_DR1_4N-NAC_123456_1234_readme.txt
2009-08-18T034353_DR1_4N-NAC_123456_1234_udm.tif
我想删除这部分:-NAC_123456_1234
其中第一部分可以由字母数字字符组成,数字部分只能由数字字符组成。
我尝试了重命名命令,但无法使其工作。我想到了类似的事情:
rename '/-[a-zA-Z]+_[0-9]+_[0-9]+//' *.*
有人可以帮助我解决我所缺少的吗?
我的重命名版本是:
rename from util-linux 2.23.2
答案1
您尝试使用的语法适用于 perlrename
命令。根据您的操作系统,该选项可能可用或可安装为prename
或perl-rename
,但您需要该选项并且不是fromrename
使用util-linux
您正在尝试的正则表达式语法。而且,即使有了这些,你也需要一些稍微不同的东西:
perl-rename 's/-[a-zA-Z]+_[0-9]+_[0-9]+//' *.*
实际上,由于您想要的只是删除最后一个之后的所有内容-
,因此您可以使用:
perl-rename 's/(.*)-(.*)(\.*)/$1$2/' *.*
不过您不需要使用这个工具。你可以运行一个小 shell 循环:
for file in *; do
ext="${file##*.}"
newName="${file%-*}.$ext"
echo mv -- "$file" "$newName"
done
这只会打印将要运行的命令。如果您对它们的正确性感到满意,请删除echo
并再次运行以实际重命名。
解释
for file in *
:将迭代当前目录中的所有文件(和目录),将每个文件保存为$file
.ext="${file##*.}"
:语法从 的开头${variable##pattern}
删除最长的匹配。所以在这里,这将删除直到最后一个的所有内容,留下文件的扩展名。pattern
$variable
.
newName="${file%-*}.$ext"
:语法从 的末尾${variable%pattern}
删除 的最短匹配。所以在这里,这将把一切留给我们直到最后。然后我们添加扩展名,这给了我们新的文件名。pattern
$variable
-
mv -- "$file" "$newName"
: 重命名文件。
答案2
如果你有zsh
,那么在那里会更容易、更安全(并且更便携)地完成:
autoload -Uz zmv
zmv -n '(*-)[[:alnum:]]##_<->_<->(*.*)' '$1$2'
(-n
如果满意,请删除(空运行))。
这是使用 shell glob(extendedglob
启用了 zsh 的)而不是正则表达式,尽管就功能而言,您可以获得与扩展正则表达式等价的功能。
*
通常匹配任意数量的字符(或字节,如果有字节不形成有效字符,这是它比(大多数)正则表达式更安全的原因之一[[:alnum:]]
是 POSIX 字符类的标准匹配。##
是一个或多个先前的原子(如+
ERE/PCRE 中的原子)。<->
是一个或多个 ASCII 十进制数字的任意序列,类似<1-10>
但没有限制。
zmv
在开始重命名之前将进行一些健全性检查,使其比rename
周围的各种变体更安全。