使用用户变量查找

使用用户变量查找

我正在尝试使用一些变量来调用 find 。到目前为止我有这个:

DIRECTORY="./ "
FILENAME=-regex" .*test.*"
find $DIRECTORY $FILENAME

效果很好。如果我将文件名更改为:

FILENAME=-regex" .*"

要列出目录中的所有文件,我收到错误:

find: paths must precede expression: ..

我究竟做错了什么?

答案1

变量的内容FILENAME

-regex .*test.*

引号不是变量值的一部分,而是 shell 语法的一部分。 shell 解析了该行,解释了引号,甚至在它发现这是一个赋值之前。

当您运行该行时find $DIRECTORY $FILENAME$FILENAME首先被其值替换。然后 shell 对变量的值执行两个扩展步骤:它将它分成单独的单词,其中变量包含空格(您恰好想要),并对每个单词执行通配符(即通配符扩展),因此.*扩展为当前目录中以点开头的文件名列表。

您的第一个代码片段没有遇到问题,因为该模式.*test.*恰好与任何文件不匹配,因此它扩展到自身。

当您需要存储多个单词时,可靠的解决方案是使用数组变量而不是字符串变量。

DIRECTORY="./"
EXPRESSION=("-regex" ".*test.*")
find "$DIRECTORY" "${EXPRESSION[@]}"

或者如果您想允许多个目录:

DIRECTORIES=("./")
EXPRESSION=("-regex" ".*test.*")
find "${DIRECTORIES[@]}" "${EXPRESSION[@]}"

"${EXPRESSION[@]}"扩展为数组中的元素列表(以单独的单词表示)。

"$foo"请注意,您应该始终在变量替换和命令替换周围使用双引号"$(foo)",除非您知道希望值发生分词和通配符。

在这里,由于您使用的是 bash,因此数组是正确的解决方案。在没有数组的 shell 中,有多种可能性。您可以使用位置参数,它们实际上是一个数组变量,但只有当您不将它们用于其他用途时才有可能:

set -- "./"                  # start with the directory
set -- "$@" -regex '.*'      # add the expression
find "$@"                    # go

另一种方法是正确引用变量的内容,为以后的分词和通配符做好准备。您可以在通配符 ( ?*[) 之前使用反斜杠以使其按字面解释。

DIRECTORY=./
EXPRESSION='-regex .\*'
find "$DIRECTORY" $EXPRESSION

另一种方法是禁用通配符set -f。在执行该find行之前。set +f如果之后需要,请务必将其重新打开。请注意,由于您使用分词,因此您将无法将空格字符作为谓词参数的一部分find

DIRECTORY=./
EXPRESSION='-regex .*'
set -f
find "$DIRECTORY" $EXPRESSION

另请参阅我试图将命令放入变量中,但复杂的情况总是失败!在 bash 常见问题解答中。

答案2

任何一个

directory=.
match=(-regex '.*test.*')
find "$directory" "${match[@]}"

或者(这里使用“,”只是为了表明观点):

directory=.
match='-regex,.*test.*'
IFS=,
set -f
find "$directory" $match

或者:

directory=.
match="-regex '.*test.*'"
eval 'find "$directory" '"$match"

答案3

您没有引用变量。因此,shell 看到的是

find ./  -regex .*

并且它扩展.*. ...

相关内容