两种方法:使用perl重命名或仅使用纯粹的bash
由于有些人不喜欢perl,我编写了只使用bash的版本。
使用rename
命令重命名文件。
介绍
是的,这是一个典型的rename
命令的任务,它专门用于此:
man rename | sed -ne '/example/,/^[^ ]/p'
For example, to rename all files matching "*.bak" to strip the
extension, you might say
rename 's/\.bak$//' *.bak
To translate uppercase names to lower, you'd use
rename 'y/A-Z/a-z/' *
更具方向性的样本
只需删除所有的空格和方括号:
rename 's/[ \[\]]*//g;' *.ext
将所有的 .jpg
文件按照编号重新命名为 1
开始:
rename 's/^.*$/sprintf "IMG_%05d.JPG",++$./e' *.jpg
示例:
touch {a..e}.jpg
ls -ltr
total 0
-rw-r--r-- 1 user user 0 sep 6 16:35 e.jpg
-rw-r--r-- 1 user user 0 sep 6 16:35 d.jpg
-rw-r--r-- 1 user user 0 sep 6 16:35 c.jpg
-rw-r--r-- 1 user user 0 sep 6 16:35 b.jpg
-rw-r--r-- 1 user user 0 sep 6 16:35 a.jpg
rename 's/^.*$/sprintf "IMG_%05d.JPG",++$./e' *.jpg
ls -ltr
total 0
-rw-r--r-- 1 user user 0 sep 6 16:35 IMG_00005.JPG
-rw-r--r-- 1 user user 0 sep 6 16:35 IMG_00004.JPG
-rw-r--r-- 1 user user 0 sep 6 16:35 IMG_00003.JPG
-rw-r--r-- 1 user user 0 sep 6 16:35 IMG_00002.JPG
-rw-r--r-- 1 user user 0 sep 6 16:35 IMG_00001.JPG
安全匹配stackoverflow问题的完整语法
有一种强大且安全的方法,使用rename
工具:
由于这是Perl常用工具,我们必须使用Perl语法:
rename 'my $o=$_;
s/[ \[\]]+/-/g;
s/-+/-/g;
s/^-//g;
s/-\(\..*\|\)$/$1/g;
s/(.*[^\d])(|-(\d+))(\.[a-z0-9]{2,6})$/
my $i=$3;
$i=0 unless $i;
sprintf("%s-%d%s", $1, $i+1, $4)
/eg while
$o ne $_ &&
-f $_;
' *
测试规则:
touch '[ www.crap.com ] file.name.ext' 'www.crap.com - file.name.ext'
ls -1
[ www.crap.com ] file.name.ext
www.crap.com - file.name.ext
rename 'my $o=$_; ...
...
...' *
ls -1
www.crap.com-file.name-1.ext
www.crap.com-file.name.ext
touch '[ www.crap.com ] file.name.ext' 'www.crap.com - file.name.ext'
ls -1
www.crap.com-file.name-1.ext
[ www.crap.com ] file.name.ext
www.crap.com - file.name.ext
www.crap.com-file.name.ext
rename 'my $o=$_; ...
...
...' *
ls -1
www.crap.com-file.name-1.ext
www.crap.com-file.name-2.ext
www.crap.com-file.name-3.ext
www.crap.com-file.name.ext
...等等...
...只要不使用-f
标志,就可以安全地使用rename
命令:文件不会被覆盖,如果出现错误,您将收到错误消息。
使用Bash和所谓的Bashisms重命名文件:
我更喜欢使用专用实用程序来完成此操作,但是即使使用纯粹的Bash(也就是没有任何fork),也可以完成这个任务。
除了Bash之外,没有使用任何其他二进制文件(没有sed
,awk
,tr
或其他):
#!/bin/bash
for file;do
newname=${file//[ \]\[]/.}
while [ "$newname" != "${newname#.}" ] ;do
newname=${newname#.}
done
while [ "$newname" != "${newname//[.-][.-]/.}" ] ;do
newname=${newname//[.-][.-]/-};done
if [ "$file" != "$newname" ] ;then
if [ -f $newname ] ;then
ext=${newname##*.}
basename=${newname%.$ext}
partname=${basename%%-[0-9]}
count=${basename#${partname}-}
[ "$partname" = "$count" ] && count=0
while printf -v newname "%s-%d.%s" $partname $[++count] $ext &&
[ -f "$newname" ] ;do
:;done
fi
mv "$file" $newname
fi
done
需要将文件作为参数运行,例如:
/path/to/my/script.sh \[*
- 用点号替换空格和方括号
- 将连续的
.-
、-.
、--
或..
序列替换为一个-
- 如果文件名没有变化,则无需进行任何操作
- 测试是否存在带有newname的文件...
- 分割文件名、计数器和扩展名,以制作带索引的newname
- 循环,如果存在带有newname的文件
- 最后重命名文件
ls
命令的输出结果的一部分作为样本贴出(大约10行)。 - F. Hauri - Give Up GitHubfile.name.ext
部分有空格吗? - programmerjakeif [[ "${file_name}" =~ '(|.*/)[^/]*([^ /]+)$' ]]; then mv "${file_name}" "${BASH_REMATCH[1]}${BASH_REMATCH[2]}"; fi
。 - programmerjake