如何使用find处理文件名中的特殊字符

如何使用find处理文件名中的特殊字符

我要查找以某些 char 开头的所有文件,例如

find . -maxdepth 1 \( -name "^m*" -a ! -name "g$" \) -print

但是如果有人创建的文件的名称中包含特殊字符怎么办?例如

touch "
marst"

尽管它符合标准,但不会被发现。我应该如何更改代码才能找到以空格开头的文件?

\( -name "^m*" -a ! -name "g$" \)不起作用,因为 find 中的文件不是“marr”而是“./marr”,这意味着这将找不到任何内容。如何更改代码以匹配单词的开头?

答案1

-name总是只匹配名称,即不匹配路径;它匹配所有的姓名。它的值是一个模式,而不是正则表达式,因此m可以使用以下命令找到以 开头的文件名

-name 'm*'

g以及以以下结尾的名称

-name '*g'

要使用正则表达式,请参阅-regex选项。

答案2

如果您想匹配以换行符开头m或后面的文件名,那么将是:

NL='
'
find . \( -name 'm*' -o -name "*${NL}m*" \) -print

请注意,至少对于 GNU find*不会匹配不形成有效字符序列的字节序列。如果这是一个潜在的问题,您可能最好使用 C 语言环境。

LC_ALL=C find . \( -name 'm*' -o -name "*${NL}m*" \) -print

例子:

$ touch mom $'two\nminutes' $'mad\x80'
$ find . -name 'm*'
./mom
$ find . \( -name 'm*' -o -name "*${NL}m*" \) -print
./two?minutes
./mom
$ LC_ALL=C find . \( -name 'm*' -o -name "*${NL}m*" \) -print
./mad?
./two?minutes
./mom

对于包含以 开头m但不包含以 结尾的行的文件名g

LC_ALL=C find . \( -name 'm*' -o -name "*${NL}m*" \) ! \(
  -name '*g' -o -name "*g${NL}*" \) -print

某些find实现有一些非标准选项来匹配文件小路(通常不姓名)使用正则表达式,但不同实现之间的行为有所不同,这里不需要这些。

例如,您需要正则表达式的地方是查找名称中的行开头m不以任何结尾的文件g(例如$'cat\nman\ndog'但不是$'plate\nmug\ncup'nor $'cat\nman\nmug'

使用 GNU find

LC_ALL=C find . -regextype posix-extended -regex \
  ".*/(([^m$NL/][^/$NL]*|m[^/$NL]*[^$NL/g]|m|)($NL|\$))*"

或者名称至少有一行以以下开头m且不以以下结尾的文件g(类似于$'mad\nmug'但不是$'ming\nmong'):

LC_ALL=C find . -regextype posix-extended -regex \
  ".*/([^/]*$NL)?m([^$NL/]*[^g$NL/])?(\$|${NL}[^/]*)"

答案3

您可以使用该-regex标志来查找是否需要 glob 提供的更复杂的匹配。它与整个路径匹配,所以如果您只想匹配文件名部分,您可以执行类似的操作

find . -maxdepth 1 -regex '/[ 
]?m[^/]*[^g]$' -print

请注意,每这个答案你不能用来\n匹配换行符,所以我们在我们的字符类中放置了一个带有空格的换行符,因为你已经要求了。

答案4

在 find 中,您不需要使用 the^或 the$作为简单名称。
寻找用途模式对于名字。模式将:

  • 匹配整个名字。从开始到结束。总是。
  • find 删除在使用该模式之前找到的任何文件的路径。
  • 唯一的特殊字符是* ?and [ ](不是 ^ 或 $)。

m因此,对于以and开头的匹配文件不是g:结束

 find . -maxdepth 1 -name 'm*[!g]' -o -name 'm'

涵盖'm'文件只有一个字符的情况。

但是,您创建的文件touch $'\nmarst'(是的,可以像 bash 中那样编写换行符)不以 开头m,而是以 new-line 开头$'\n'。没有办法在简单模式中进行交替,但您可以使用-ofind 的 OR ( ) 选项:

find . -maxdepth 1 \( -name 'm*' -o -name $'\n'"m*" \) -a ! -name '*g'

如果要求更长,这将变得困难。
对于非常复杂的字符串,可以-regex使用 find 选项。

相关内容