我在 Ubuntu 上使用以下命令rename
(使用sudo apt-get rename
)来重命名在正则表达式中具有给定字符的所有文件:
find . -execdir rename 's/[^A-Za-z0-9_.@+,#!?:&%~\(\)\[\]\/ \-]/?/g' * {} \;
这工作得很好,所有其他字符都更改为?
。现在我想包括诸如此类的法语字符àèìòù
。所以我添加À-ÿ
到我的正则表达式中:
find . -execdir rename 's/[^A-Za-zÀ-ÿ0-9_.@+,#!?:&%~\(\)\[\]\/ \-]/?/g' * {} \;
但不知何故,这些文件没有被重命名,并且在运行此命令后它们似乎已损坏,À-ÿ
因为我无法再删除它们。
将它们包含在重命名正则表达式中的正确方法是什么?
答案1
假设这些文件名以 UTF-8 编码,请使用:
find . -depth -execdir rename -n '
utf8::decode$_ or die "cannot decode $_\n";
s{[^\w.\@+,#!?:&%~()\[\]/ -]}{?}gs;
utf8::encode$_;
' {} +
(快乐时去掉-n
)。
请注意,某些 BSD 实现的find
不会在文件名前加上前缀,./
因此-execdir
如果文件名以 开头,命令可能会失败-
。使用 变体rename
,您应该能够通过更改rename -n
为 来解决这个问题rename -n --
(这对所有其他 perl 变体不起作用rename
)。
在现代版本中perl
,\w
(对于单词字符)是任何字母数字(任何字母文字,而不仅仅是拉丁语),或下划线字符加上其他字符连接器标点字符加上 Unicode 标记(例如,包括结合尖锐的口音后面的字符e
以 ) 的分解形式表示é
。
如果您想更具限制性,则\w
可以使用\p{latin}\p{mark}0-9_
仅包含拉丁字母中的字母(而不是西里尔字母、希腊语......)、组合变音符号(尽管不限于通常与拉丁字母一起使用的变音符号),以及仅印度-阿拉伯十进制数字(而不是其他类型的数字)和下划线(而不是其他连接标点字符)。
如果不使用utf8::decode
,perl
将假定字符以 iso8859-1 单字节字符集进行编码(例如,其中0xc3 0xa9
( 的预组合形式的 UTF-8 编码é
) 是Ã
©
)。
或者,您可以使用zsh
(它将根据区域设置的编码解码字符(请参阅 的输出locale charmap
)):
autoload zmv # best in ~/.zshrc
zmv -n '(**/)(*)(#qD)' '$1${2//[^][:alnum:]_.@+,#!?:&%~()[\/ -]/?}'
任何在您的语言环境中不形成有效字符的字节序列中的每个字节也将被转换为 a ?
(rename
上面的内容会因错误而终止cannot decode
)。
它[[:alnum:]]
使用您的区域alnum
设置类别,因此不太可能包含其他 Unicode 连接器标点符号或标记字符。
perl
在and中zsh
(但通常不在其他工具中),类似的范围[a-zÀ-ÿ]
基于字符的代码点。例如,该范围将匹配该代码点范围内的字符(其中包括非字母字符,并且并非拉丁字母中的所有字符或在法语中使用的字符,例如azÀÿ
)。在 中,您还需要添加以便能够在 perl 代码中使用和的 UTF-8 编码。\u0061\u007A\u00C0\u00FF
abcdefghijklmnopqrstuvwxyzÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ
œ
perl
use utf8
À
ÿ