我是重命名新手,并且有许多帕斯卡大小写的文件和文件夹,我想将它们转换为小写,并用连字符分隔。我想递归地对文件和文件夹运行该命令。
例如。
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
成为捕获的组。该表达式还会捕获首字母大写字母,在开头给出一个破折号。
像这样的东西会变成FooBar
(foo-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
此处用于试运行)。