给定一个.txt
文件,其中包含名为的文件列表:
2015_273_2_1_1__Your_Favorite_Home_Movie_1.mov
2015_273_2_1_1__Your_Favorite_Home_Movie_2.mov
2015_273_2_1_1__Your_Favorite_Home_Movie_3.mov
如何将数字之间的所有 _
重命名为 .
而不更改字母之间的数字?
我希望输出为:
2015.0273.2.1.1__Your_Favorite_Home_Movie_1.mov
2015.0273.2.1.1__Your_Favorite_Home_Movie_2.mov
2015.0273.2.1.1__Your_Favorite_Home_Movie_3.mov
等
sed -E '/s/{0..9}_{0..9}/{0..9}.{0..9}/' /Users/medialab/Desktop/ls.txt
给我一个错误invalid command code .
在我问的时候,如果目标是目录中的文件而不是rename
文件中的文件列表,那么这对mv
或.txt
有什么用处?
答案 0 :(得分:2)
TL; DR:以下正则表达式执行替换:
sed -E 's/([0-9]{4})_([0-9]{3})_([0-9])_([0-9])_([0-9])/\1.0\2.\3.\4.\5/' ls.txt
[0-9]
而不是{0..9}
。使用正则表达式进行字符串替换时,可以使用括号定义的匹配组。您可以使用\n
来引用这些数字,其中 n 是匹配组的编号(整个匹配为0)。
s/(foo)bar/\1-\0/ => foo-foobar
此外,sed命令不以/
开头。
最后,当你想要正则表达式中有一定数量的字符时,你应该使用*
(O到N),+
(1到N)或字符数你想要{MIN,MAX}
。
注意: -E
选项用于扩展正则表达式,这是一种更常见的正则表达式。您还可以在Linux上使用等效的-r
选项。
答案 1 :(得分:0)
OSX没有像Linux这样的内置rename
命令。如果您从外部源(如自制软件或macports或fink等)安装一个,那么确定您正在使用哪一个以及它的选项是有帮助的。我会在不参考rename
的情况下回答,因为它不会对使用公共广告的普通macOS有用。 (说实话,Linux也没有一个rename
- 我知道在不同的Linux发行版中有三个不同的rename
命令,所有这些命令都有不同的选项和用法。)
我可能会使用awk而不是sed:
$ awk 'BEGIN{FS=OFS="__"} {f=$0; gsub(/_/,".",$1); printf "mv %s %s\n", f, $1 $2}' list.txt
mv 2015_273_2_1_1__Your_Favorite_Home_Movie_1.mov 2015.273.2.1.1Your_Favorite_Home_Movie_1.mov
mv 2015_273_2_1_1__Your_Favorite_Home_Movie_2.mov 2015.273.2.1.1Your_Favorite_Home_Movie_2.mov
mv 2015_273_2_1_1__Your_Favorite_Home_Movie_3.mov 2015.273.2.1.1Your_Favorite_Home_Movie_3.mov
为便于阅读而分手,即:
BEGIN{FS=OFS="__"}
- 将字段分隔符设置为双下划线{f=$0;
- 存储原始文件名gsub(/_/,".",$1);
- 用__
printf "mv %s %s\n", f, $1 $2}'
- 打印我们的命令。如果看起来正确,请通过/bin/sh
进行管道。请注意,如果您想要使用标点符号和特殊字符,那么这就不是一种方法。以下内容取决于由${var/re/text}
构造引起的bash,它不是POSIX的一部分。
while read file; do
[ -f "$file" ] || continue # skip files that don't exist
lhs="${file%__*}"
lhs="${lhs//_/.}"
echo mv -v "$file" "${lhs}__${file#*__}"
done < list.txt
虽然时间较长,但也更容易阅读和维护。你可以包含一些关于跳过不存在的文件的逻辑,这很好。
答案 2 :(得分:0)
GNU sed
:
$ sed -r ':loop;s/([0-9])_([0-9])/\1.\2/;tloop' input.txt
2015.273.2.1.1__Your_Favorite_Home_Movie_1.mov
2015.273.2.1.1__Your_Favorite_Home_Movie_2.mov
2015.273.2.1.1__Your_Favorite_Home_Movie_3.mov
# add a 0 before the month.
$ sed -r ':loop;s/([0-9])_([0-9])/\1.\2/;tloop;s/[0-9]+/0&/2' input.txt
2015.0273.2.1.1__Your_Favorite_Home_Movie_1.mov
2015.0273.2.1.1__Your_Favorite_Home_Movie_2.mov
2015.0273.2.1.1__Your_Favorite_Home_Movie_3.mov
修改强>
如果目标是目录中的文件,只需执行以下操作:
# origion files.
$ find . -name '*.mov'
./2015_273_2_1_1__Your_Favorite_Home_Movie_1.mov
./2015_273_2_1_1__Your_Favorite_Home_Movie_2.mov
./2015_273_2_1_1__Your_Favorite_Home_Movie_3.mov
# if don NOT use the e modifier of s command, we can get the final command.
$ find . -name '*.mov' |sed -r 'h;:loop;s/([0-9])_([0-9])/\1.\2/;tloop;s/[0-9]+/0&/2;G;s/([^\n]+)\n(.+)/mv \2 \1/'
mv ./2015_273_2_1_1__Your_Favorite_Home_Movie_1.mov ./2015.0273.2.1.1__Your_Favorite_Home_Movie_1.mov
mv ./2015_273_2_1_1__Your_Favorite_Home_Movie_2.mov ./2015.0273.2.1.1__Your_Favorite_Home_Movie_2.mov
mv ./2015_273_2_1_1__Your_Favorite_Home_Movie_3.mov ./2015.0273.2.1.1__Your_Favorite_Home_Movie_3.mov
# use e modifier of s command to execute the substituted command.
$ find . -name '*.mov' |sed -r 'h;:loop;s/([0-9])_([0-9])/\1.\2/;tloop;s/[0-9]+/0&/2;G;s/([^\n]+)\n(.+)/mv \2 \1/e'
# changed files.
$ find . -name '*.mov'
./2015.0273.2.1.1__Your_Favorite_Home_Movie_1.mov
./2015.0273.2.1.1__Your_Favorite_Home_Movie_2.mov
./2015.0273.2.1.1__Your_Favorite_Home_Movie_3.mov
说明:
h
命令将原始文件名保存在hold space
。:loop;s/([0-9])_([0-9])/\1.\2/;tloop;s/[0-9]+/0&/2
重命名_
到numerals
之间的所有.
,并在月之前添加0
。G
命令将hold space
附加到pattern space
,然后pattern space
中的内容为CHANGED_FILENAME\nORIGIN_FILENAME
。s/([^\n]+)\n(.+)/mv \2 \1/
将命令与CHANGED_FILENAME
和ORIGIN_FILENAME
合并; e
命令的s
修饰符执行上面汇编的命令,这将完成实际工作。P.S:
sed -r 's/([0-9])_([0-9])/\1.\2/g'
无法处理连续匹配结果,例如:3_2_1
(2_1
未替换)。-E
用于BSD sed
。