我在客户的目录中使用它来重命名文件,并根据他们的要求将每个单词的首字母大写:
rename 's/\b(\w)/\u$1/g' *
这可以正常工作,但是它也会将扩展名的首字母大写,因此我使用它来解决这个问题:
rename 's/\.Txt$/.txt/' *.Txt
如果文件夹中的大多数文件都具有相同的扩展名(通常如此),则此方法可以正常工作,但如果文件混合在一起,则会很麻烦。
为了解决这个问题,我创建了一个如下所示的小脚本(不要笑!):
#!/bin/bash
rename 's/\.Txt$/.txt/' *.Txt
rename 's/\.Doc$/.doc/' *.Doc
rename 's/\.Docx$/.docx/' *.Docx
...
rename 's/\.Xlsx$/.xlsx/' *.Xlsx
我忽略了“无法重命名 *.Txt *.txt:没有此文件或目录”错误,如果我发现缺少扩展名,我只需将该行添加到我的脚本中。
我认为这无关紧要,但这些文件位于 Windows 服务器文件共享中,而我使用 Ubuntu 16.04LTS 访问它。如果这确实有关系,那么我可以先将它们复制到本地驱动器,在 Ubuntu 中运行命令,然后根据需要将文件移回。
有没有办法修改第一个重命名命令以忽略扩展名并将其保留为小写?我可以在更高级别的目录中运行新命令,并让它遍历所有子目录吗?
答案1
实现此目的的一种方法可能是使用负面后视仅当单词边界 - 单词字符序列前面没有文字句点时才匹配,例如给定
$ ls
alan's file.txt bar.txt foo
然后
$ rename -n 's/(?<!\.)\b\w*/\u$&/g' *
rename(alan's file.txt, Alan'S File.txt)
rename(bar.txt, Bar.txt)
rename(foo, Foo)
假设你也想避免将复数首字母大写s
,我们可以将其修改为
$ rename -n 's/(?<![.'\''])\b\w*/\u$&/g' *
rename(alan's file.txt, Alan's File.txt)
rename(bar.txt, Bar.txt)
rename(foo, Foo)
甚至
$ rename -n 's/(?<![[:punct:]])\b\w*/\u$&/g' *
rename(alan's file.txt, Alan's File.txt)
rename(bar.txt, Bar.txt)
rename(foo, Foo)
答案2
这将使除最后一个扩展名之外的每个单词的首字母大写:
rename -n 's/\b(.+?)\b/\u$1/g; s/(.+)\.(.)/$1\.\l$2/' *
我使用这些文件进行了测试:
$ ls -1
'a file with a '$'\n''new line.foo'
'a file with spaces.txt'
justonelongfilename.ext
no-extensions-here
this.has.many.extensions.pdf
并将其重命名为:
$ rename -n 's/\b(.+?)\b/\u$1/g; s/(.+)\.(.)/$1\.\l$2/' *
a file with a
new line.foo -> A File With A
New Line.foo
a file with spaces.txt -> A File With Spaces.txt
justonelongfilename.ext -> Justonelongfilename.ext
no-extensions-here -> No-Extensions-Here
this.has.many.extensions.pdf -> This.Has.Many.Extensions.pdf
诀窍是先将每个首字母大写,忽略扩展名,然后再返回并将扩展名改为小写:
s/\b(.+?)\b/\u$1/g;
:.+?
是一个非贪婪模式,这意味着它将找到最短的匹配。由于它由单词边界(\b
)固定,因此它将找到所有单词(全部因为最后的g
)。然后将它们替换为大写(首字母大写)版本的单词(\l$1
)。s/(.+)\.(.)/$1\.\l$2/
:.+
是贪婪的,所以它会找到最长的匹配。这意味着最长的字符串直到最后的,之后是扩展名(如果有)。我们用扩展名( )、a和首字母再次小写的扩展名( ).
之前的所有内容替换匹配。$1
.
\l$2
递归也很简单。如果你的 shell 是 bash(如果你不知道,可能就是),你可以使用 globstar 选项,匹配**
0 个或更多子目录:
shopt -s globstar
现在,像这样运行重命名命令(这也适用于当前目录下的任何文件):
rename -n 's/\b(.+?)\b/\u$1/g; s/(.*)\.(.)/$1\.\l$2/' **
要将其限制为仅具有扩展名的文件或目录,请使用**/*.*
而不是**
。
或者,使用find
:
find /path/to/dir -exec rename -n 's/\b(.+?)\b/\u$1/g; s/(.*)\.(.)/$1\.\l$2/' {} +
并且,限制那些具有扩展名的文件和目录:
find /path/to/dir -name '*.*' -exec rename -n 's/\b(.+?)\b/\u$1/g; s/(.*)\.(.)/$1\.\l$2/' {} +
注意所有这些解决方案都会愉快地重命名目录和文件。如果您不想这样,请小心告诉它递归的位置,或者给它一个更具体的模式,例如*.txt
。
在所有示例中,删除 -n 以使它们真正执行某些操作。-n
导致它rename
只是打印要执行的操作,而实际上不执行任何操作。对测试有用。
答案3
最明智的方式是处理所有“单词”(使用单词边界\b
并通过$1
任何第一个字符引用),包括扩展名,然后将扩展名本身小写:
$ prename -nv 's/\b(.)/\u$1/g;s/^(.*)\.(.*)/$1.\l$2/' *
another filename trispaced.txt renamed as Another Filename Trispaced.txt
filename_with_underschore.txt renamed as Filename_with_underschore.txt
one filename.txt renamed as One Filename.txt
请注意,这不适用于带有下划线的文件名,即“单词”边界被视为空白(制表符、空格、换行符 - 希望它们无论如何都不应该出现在文件名中)。
prename
请注意,为了实现可移植性,使用ksh
,其中rename
实际上是一个内置命令,而不是独立的perl
可执行文件。
答案4
只需使用rename 's/\b(\w)/\u$1/' *
不带 g 标志的标志即可。g
标志表示“全局 = 多次执行”。您第一次在文件名中执行,并且您不想在第二次执行时将其变为大写,对吗?