重命名要大写的文件但不影响文件扩展名

Ala*_*lan 7 command-line rename batch-rename

我在客户的目录上使用它来重命名文件,每个单词的第一个字母根据他们的要求大写:

rename 's/\b(\w)/\u$1/g' *

这工作正常,但它也将扩展名的第一个字母大写,所以我用它来解决这个问题:

rename 's/\.Txt$/.txt/' *.Txt
Run Code Online (Sandbox Code Playgroud)

如果文件夹中的大多数文件具有相同的扩展名(通常是正确的),则可以正常工作,但如果它们非常混合,则很痛苦。

为了解决这个问题,我创建了一个看起来像这样的小脚本(不要笑!):

rename 's/\.Txt$/.txt/' *.Txt
Run Code Online (Sandbox Code Playgroud)

我忽略了“无法重命名 *.Txt *.txt:没有这样的文件或目录”错误,如果我发现缺少扩展名,我只需将该行添加到我的脚本中。

我认为这无关紧要,但文件位于 Windows 服务器文件共享上,但我使用 Ubuntu 16.04LTS 访问它。如果确实重要,那么我可以先将它们复制到我的本地驱动器,在 Ubuntu 中运行命令,然后根据需要将文件移回。

有没有办法修改第一个重命名命令以忽略扩展名并将它们保留为小写?我可以在更高级别的目录中运行新命令,并让它在所有子目录中递归吗?

ste*_*ver 7

实现此目的的一种方法可能是使用Negative Lookbehind仅匹配单词边界 - 当前面没有文字句点(例如给定)时的单词字符序列

$ ls
alan's file.txt  bar.txt  foo
Run Code Online (Sandbox Code Playgroud)

然后

$ rename -n 's/(?<!\.)\b\w*/\u$&/g' *
rename(alan's file.txt, Alan'S File.txt)
rename(bar.txt, Bar.txt)
rename(foo, Foo)
Run Code Online (Sandbox Code Playgroud)

假设您还想避免将复数大写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)
Run Code Online (Sandbox Code Playgroud)

甚至

$ 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)
Run Code Online (Sandbox Code Playgroud)


ter*_*don 5

这将大写每个单词的第一个字母,除了最后一个扩展名:

rename -n 's/\b(.+?)\b/\u$1/g; s/(.+)\.(.)/$1\.\l$2/' *
Run Code Online (Sandbox Code Playgroud)

我用这些文件进行了测试:

$ 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
Run Code Online (Sandbox Code Playgroud)

它会将它们重命名为:

$ 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
Run Code Online (Sandbox Code Playgroud)

诀窍是首先将每个第一个字母大写,忽略扩展名,然后返回并将扩展名设为小写:

  • s/\b(.+?)\b/\u$1/g;:.+?是一种非贪婪模式,这意味着它将找到最短的匹配项。由于它以单词边界 ( \b)为锚定,因此将找到所有单词(都是因为 final g)。然后将它们替换为它们自己的大写(首字母大写)版本 ( \l$1)。

  • s/(.+)\.(.)/$1\.\l$2/: the.+是贪婪的,所以它会找到最长的匹配。这意味着最长的字符串直到 final .,之后将是扩展名(如果有)。我们用扩展名 ( $1)之前的所有内容替换匹配项, a.和第一个字母再次小写的扩展名 ( \l$2)。


递归也很容易。如果您的 shell 是 bash(如果您不知道,它可能是),您可以使用 globstar 选项来**匹配 0 个或多个子目录:

shopt -s globstar
Run Code Online (Sandbox Code Playgroud)

现在,像这样运行重命名命令(这也适用于当前目录中的任何文件):

rename -n 's/\b(.+?)\b/\u$1/g; s/(.*)\.(.)/$1\.\l$2/' **
Run Code Online (Sandbox Code Playgroud)

将它与扩展限制为仅文件或目录,使用**/*.*代替**

或者,使用find

find /path/to/dir -exec rename -n 's/\b(.+?)\b/\u$1/g; s/(.*)\.(.)/$1\.\l$2/' {} +
Run Code Online (Sandbox Code Playgroud)

并且,限制为那些带有扩展名的文件和目录:

find /path/to/dir -name '*.*' -exec rename -n 's/\b(.+?)\b/\u$1/g; s/(.*)\.(.)/$1\.\l$2/' {} +
Run Code Online (Sandbox Code Playgroud)

请注意,所有这些解决方案都会愉快地重命名目录和文件。如果您不想要那样,请小心告诉它递归的位置,或者给它一个更具体的模式,例如*.txt.


在所有示例中,删除 -n 以使它们实际执行某些操作。-n原因rename简单地打印的内容会做,实际上并不做任何事情。用于测试。