PascalCase 转为小写连字符

PascalCase 转为小写连字符

我是重命名新手,并且有许多帕斯卡大小写的文件和文件夹,我想将它们转换为小写,并用连字符分隔。我想递归地对文件和文件夹运行该命令。

例如。

  • MyFile.txt变成my-file.txt
  • MyPhoto.jpg变成my-photo.jpg

然而:

  • ABird.jpg应保持不变
  • USBDisk应保持不变
  • 对于MyUSBDisk,我对 My-USBDisk 或 my-USBDisk 很满意 我还有另一个命令将所有大写字母转换为小写字母,因此在此之前最重要的事情是将连字符放在正确的位置

我的尝试没有成功:

find /path/directory -depth -exec rename 's/\([A-Z]\)/-\L\$1/g' {} \;

怎么解决?我正在使用 Linux Mint 21。

答案1

rename 's/\([A-Z]\)/-\L\$1/g'

有几件事。 Perl 正则表达式比基本正则表达式更接近 POSIX 扩展正则表达式,并且\(/\)匹配文字括号,而分组是在没有反斜杠的情况下完成的。另外,\$使$右侧的文字$1成为捕获的组。该表达式还会捕获首字母大写字母,在开头给出一个破折号。

像这样的东西会变成FooBarfoo-bar这里只是重命名部分):

rename 's/([[:lower:]])([[:upper:]])/$1-\L$2/g; s/^([[:upper:]])/\L$1/;' ...

但也会USBDisk.img变成uSBDisk.img。如果第一个字母之后还有另一个大写字母,您可以添加负向先行检查以禁止替换。这将不会发生USBDisk.img,但仍然会DiskONE.img变成diskONE.img

rename 's/([[:lower:]])([[:upper:]])(?![[:upper:]])/$1-\L$2/g; s/^([[:upper:]])(?![[:upper:]])/\L$1/;' ...

或者,如果文件名中的任意位置连续有两个大写字母,则跳过整个过程:

rename 'unless (/[[:upper:]]{2}/) { s/([[:lower:]])([[:upper:]])/$1-\L$2/g; s/^([[:upper:]])/\L$1/ }' ...

您可能需要rename -n -v先进行测试以查看更改而不进行更改。

当然,这仍然会Foo-Bar.jpg变成foo-Bar.jpg,但我现在将修复它作为练习......


rename使用运行find,您需要添加适当的-exec语法,例如

find /path/directory -depth -exec rename '...' {} \;

或者使用,一次-exec {} +给出多个文件名:rename

find /path/directory -depth -exec rename '...' {} +

就像 Stéphane 评论的那样,您可能希望将重命名限制为仅文件名部分。将-d选项添加到rename或切换到-execdir而不是-exec. (非标准、GNU/BSD)

答案2

zsh

autoload -Uz zmv
zmv -n '(**/)(*[[:lower:]][[:upper:]]*~*[[:upper:]](#c2)*)' \
       '$1${${2//(#b)([[:lower:]])([[:upper:]])/$match[1]-$match[2]}:l}'

我们重命名至少有一个<lower><upper>序列但没有 的文件,在小写和大写字符之间<upper><upper>插入 a并将整个文件转换为小写。-

-n此处用于试运行)。

相关内容