我需要重命名目录中的文件,例如
11-Vnnn_S2_L001_aaa_bbb_ccc_ddd.ext
到
Vnnn.ext
有没有办法basename
在 Linux 中使用命令来做到这一点?
我对编码非常陌生,所以我很乐意提供一些解释。
答案1
一个简单的循环:
for name in *.ext; do
newname=${name%%_*}.ext
newname=${newname#*-}
echo mv -- "$name" "$newname"
done
这将循环遍历.ext
当前目录中以结尾的所有名称(因此首先更改为有问题的目录)。对于每个这样的名称,newname
变量首先设置为名称的第一个_
字符之前的部分,并.ext
添加到末尾。-
然后删除第一个字符之前的值以创建最终newname
值。
这里使用的两个参数替换${variable%%pattern}
和分别从值的末尾${variable#pattern}
删除最长的匹配子字符串,从开头删除最短的匹配子字符串。pattern
$variable
运行该echo
命令以查看它是否执行正确的操作,然后删除echo
前面的mv
内容以实际重命名文件。
答案2
您可以尝试使用rename
:
rename 's/^[^-]+-([^_]+).+(\.[^.]+)$/$1$2/' *.ext
-
将提取第一个和第一个之间的部分_
,并将扩展名附加到其中。先尝试rename -n '...'
一下,满意后删除-n
。
该语法使用捕获组将原始文件名分解为
- 从开始到第一个
-
:的所有内容^[^-]+-
,即以一个或多个字符开头的字符串不是-
,接着是一个-
。 - 一个“捕获组”,包含此后的所有内容,直到但不包括第一个
_
:([^_]+)
,即一个或多个不是的字符- 实际值稍后可以在替换文本中_
引用$1
- 之后的一切,直到但不包括最后的
.
:.+
实际上只意味着“一个或多个任何类型的字符” - “直到最后.
”的含义来自最后一部分的定义 - 一个“捕获组”,包含最后一个
.
以及之后直到字符串结尾的所有内容:(\.[^.]+)$
- 此公式强制捕获组内容以文字开头.
,然后仅包含以下字符不是.
,直到字符串末尾$
;只有这样才能确保前一组吞噬除最后一组之外的所有内容.
。同样,实际内容稍后可以引用为$2
(因为它是正则表达式中的第二个捕获组)。
然后,替换文本仅包含两个捕获组的实际内容:$1$2
。
答案3
与 AdminBees 解决方案类似,也许您更容易适应其他问题,您可以使用 bash 内置功能,如下所示:
for file in *
do
if [[ "$file" =~ ^[^-]*-([^_]+)_.*\.ext$ ]]
then
mv "$file" "${BASH_REMATCH[1]}.ext"
fi
done
那有什么作用:
for
多变的 in
空格分隔的项目列表
循环遍历列表中的每个项目,设置多变的do
并执行和之间的命令done
。
办法当前目录中的每个文件, 尝试echo *
。
[[
是 bashs 旧test
命令的内置版本:文档
现在来解压这个复杂的正则表达式:
^
-输入行的开头
其次是[^-]
-任何字符,除了 -
, *
-重复任意次数,随后是-
.现在,之间的部分()
就是您感兴趣的部分。Bash 将括号之间匹配的部分保存到数组中BASH_REMATCH
(关联)。其正则表达式是[^_]+
,意思是任何字符,除了 _
,至少重复一次,随后是_
.
.
-任何字符,*
重复任意次数*,后跟\.
文字.
(请参阅这里),然后是ext
和$
,输入结束(行)。
由于输入是我们的文件名,因此提取-
和之间的第一部分_
并将其保存到${BASH_REMATCH[1]}
.如果输入文件名与该模式匹配,我们只需使用常规的 oldmv
重命名$file
为our_matched_part.ext
,如果您的文件名不包含空格,则引号并不是绝对必要的,但这是一个很好的做法。
希望有帮助!
编辑:啊,废话。 AdminBee 编辑了他们的帖子,我没有看到。那好吧...
*-something_*.ext
EDIT2:您可以通过添加更多文字部分(例如数字)来进一步限制正则表达式仅重命名特定文件,而不是每个文件[0-9]+
。
答案4
ls 11-Vnnn_S2_L001_aaa_bbb_ccc_ddd.ext| awk -F "[-_]" '{print "mv " $0" " $2".ext"}' |sh
测试并运行良好