(GNU) find 可以执行不区分重音的(变音符号不敏感的)搜索吗?

jai*_*met 7 find

我想对目录层次结构中的文件执行不区分重音的搜索。

\n
$ touch a \xc4\x85 \xc3\xa4 \xc3\xa0 \xc3\xa1 \xc3\xa2\n$ find . -iname \'*a*\'\n./a\n# How do I get find to return all 6 filenames?\n
Run Code Online (Sandbox Code Playgroud)\n

我正在运行 Debian 11,Bullseye

\n

我的校对能力很弱!

\n

是否有一个选项、区域设置或其他一些方法可以让我以不区分重音的方式进行查找工作?

\n

根据评论中的要求,locale返回:

\n
LANG=en_GB.UTF-8\nLANGUAGE=en_GB:en\nLC_CTYPE="en_GB.UTF-8"\nLC_NUMERIC="en_GB.UTF-8"\nLC_TIME="en_GB.UTF-8"\nLC_COLLATE="en_GB.UTF-8"\nLC_MONETARY="en_GB.UTF-8"\nLC_MESSAGES="en_GB.UTF-8"\nLC_PAPER="en_GB.UTF-8"\nLC_NAME="en_GB.UTF-8"\nLC_ADDRESS="en_GB.UTF-8"\nLC_TELEPHONE="en_GB.UTF-8"\nLC_MEASUREMENT="en_GB.UTF-8"\nLC_IDENTIFICATION="en_GB.UTF-8"\nLC_ALL=\n
Run Code Online (Sandbox Code Playgroud)\n

raf*_*raf 2

TL;DR 滚动到最后

这是一个很棒的问题。谢谢你的提问。

据我所知,可以执行不区分重音的搜索,但默认情况下不会,也不会自动执行。您可以使用以下命令找到所有六个示例文件:

find . -name '[[=a=]]'
Run Code Online (Sandbox Code Playgroud)

这是标准 POSIX glob 表示法,用于表示所有类似但可能带有重音的字符。

因此,如果您知道所有可能有重音版本的字符,则可以在搜索中明确使用上述符号。例如:

find . -name 'fran[[=c=]]ais' # To match a cedilla
Run Code Online (Sandbox Code Playgroud)

但这是乏味的并且非常令人不满意。

请注意,该[[=a=]]表示法也可以用于没有任何重音版本的字符。所以[[=k=]]会匹配k

因此,我建议创建一个脚本(带重音符号),该脚本在命令行上接受一个字符串,用[[=x=]]它的版本替换每个字母,并打印出结果,然后您可以将其与find一起使用。例如:

#!/usr/bin/env perl
print join('', map { /\p{Letter}/ ? "[[=$_=]]" : $_ } split //, $ARGV[0]), "\n";
Run Code Online (Sandbox Code Playgroud)

将其与find一起使用可能如下所示:

find . -name "`accented a`"
Run Code Online (Sandbox Code Playgroud)

如果您希望它感觉自动,并且仅以最简单的方式使用find ,您可以创建一个结合find有重音的shell 脚本 ( ffind ) :

#!/bin/sh
find "$1" -name "`accented \"$2\"`"
Run Code Online (Sandbox Code Playgroud)

然后你可以这样做:

ffind . a
Run Code Online (Sandbox Code Playgroud)

但这将导致无法使用find的其他谓词。

当您需要时,您必须明确使用真正的查找重音符号(如上所示)。

这里

更聪明的解决方案是对find ( ffind )进行包装,它扫描-name-iname参数,并有效地将重音应用于后面的参数,然后执行生成的修改后的find命令。例如:

#!/usr/bin/env perl
use warnings;
use strict;
# ffind - find wrapper that makes -name and -iname accent-insensitive
my @cmd;
while (@ARGV)
{
    # Gather command line arguments
    push @cmd, shift @ARGV;

    # Make -name and -iname arguments accent-insensitive
    if ($cmd[-1] =~ /^-i?name$/ && @ARGV)
    {
        push @cmd, join('', map { /\p{Letter}/ ? "[[=$_=]]" : $_ } split //, shift @ARGV);
    }
}
exec 'find', @cmd;
Run Code Online (Sandbox Code Playgroud)

然后您可以这样做来查找所有六个示例文件:

ffind . -name a
Run Code Online (Sandbox Code Playgroud)

当然,您可以将其命名为find并将'find'最后一行的 更改为'/usr/bin/find',这将使find透明地不区分重音:

find . -name a
Run Code Online (Sandbox Code Playgroud)

遗憾的是,这整个方法仅适用于某些系统,例如 Debian 12,但并非全部。:-(