是否可以从多个名称过滤器来自文件的 bash 脚本运行 find 命令?

是否可以从多个名称过滤器来自文件的 bash 脚本运行 find 命令?

我试图对文件夹进行一些跟踪,并希望使用文件中的 find -name 过滤器。因此,我准备了一个名为 filter_files 的文件,其中包含过滤器,例如:

cat filter_files:
-name "a.txt" -o -name "b.txt"

我尝试运行 find 命令并添加上述过滤器,但它什么也不返回,如果我写入文件的内容并将其粘贴到 find 命令中,它就会成功。

我的 bash 文件中的相关行是:

local filter=$(cat $filter_files)
find_files=$(find "$path" -type f \( $filter \) )

你能向我解释一下我是否可以做我想做的事吗?如果是的话,我怎样才能让它发挥作用?

答案1

如果文件包含

-name "a.txt" -o -name "b.txt"

你跑

find "$path" -type f \( $(cat file) \) 

然后,shellcat通过分词运行输出,产生参数-name, "a.txt", -o, -name, 和"b.txt",其中引号实际上是参数的一部分。 (请注意,引号也不会保护空格。像这样的输入字符串"foo bar"将导致两个字段"foobar"。此外,拆分的结果将通过文件名生成/通配符,因此类似的内容foo*.txt会在此时扩展,而不是按find原样传递。)

这是因为分词相当简单,仅有的在空白处分割,确实如此不是通过完整的 shell 语法解析运行输出。 (如果确实如此,那将非常危险,因为它还意味着始终递归地运行任何扩展,包括命令替换。不可能相对安全地使用 shell 来处理任意数据。)

如果您想让文件中的部分经过完整的语法处理,您必须使用 运行命令eval,例如:

eval 'find "$path" -type f \( '"$(cat file)"' \)'

这里,外壳处理完引号和命令替换后,eval得到下面的字符串,然后将其作为shell命令进行处理,包括引号处理和所有扩展。

find "$path" -type f \( -name "a.txt" -o -name "b.txt" \)

(请注意,这意味着如果文件包含 eg "$(reboot)",该命令将运行。但是,我留待"$path"内壳扩展,以便它不会被双重处理。)

您可以分多个步骤执行上述操作,例如,通过将文件中的单词分配给带有 的数组eval,然后在最终命令中使用该数组。想法和注意事项是相同的。


您可能希望重新考虑文件的格式。即使例如将每个参数放在单独的行上(并取消引号)也会使其更易于解析。

例如,如果文件是:

-name
a.txt
-o
-name
foo bar.txt

您可以执行类似的操作,将readarray每个输入行读取到单独的数组元素:

#!/bin/bash
readarray -t args < file 
find "$path" -type f \( "${args[@]}" \)

(这仍然受到限制,因为它无法处理带有换行符的文件名,但这些情况可能比较罕见,并且也会产生其他问题。)

话又说回来,如果您需要的只是-name匹配,您可以让文件仅列出模式,并-o -name以编程方式生成样板文件。

也可以看看:

答案2

使用:

您需要单独的行,并-o从文件中删除,以使其变得容易。

find "$path" -type f $(sed '1q;d' filter_files) -o $(sed '2q;d' filter_files)

或者:

单弦。

filter_conditions=$(<sed '1q;d' filter_files)
find_files=$(find "$path" -type f \( $filter_conditions \))

相关内容