Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays find命令的参数展开_Arrays_Bash_Find_Variable Expansion - Fatal编程技术网

Arrays find命令的参数展开

Arrays find命令的参数展开,arrays,bash,find,variable-expansion,Arrays,Bash,Find,Variable Expansion,考虑代码(变量$i之所以存在,是因为它在一个循环中,为模式添加了几个条件,例如*.a和*.b,…但为了说明这个问题,只有一个通配符模式就足够了): 如果在包含文件bar和foo.a的文件夹上运行,它将工作,输出: ./foo.a ./bar 但是,如果您现在向文件夹中添加一个新文件,即zoo.a,则它将不再工作: find: paths must precede expression: zoo.a 大概是因为*.$i中的通配符被shell扩展为foo.a zoo.a,从而导致无效的find命

考虑代码(变量
$i
之所以存在,是因为它在一个循环中,为模式添加了几个条件,例如
*.a
*.b
,…但为了说明这个问题,只有一个通配符模式就足够了):

如果在包含文件
bar
foo.a
的文件夹上运行,它将工作,输出:

./foo.a
./bar
但是,如果您现在向文件夹中添加一个新文件,即
zoo.a
,则它将不再工作:

find: paths must precede expression: zoo.a
大概是因为
*.$i
中的通配符被shell扩展为
foo.a zoo.a
,从而导致无效的
find
命令模式。因此,一种修复方法是在通配符模式周围加引号。除非它不起作用:

  • 使用单引号--
    PATTERN=“-name bar-或-name'*.$i'
    时,
    find
    命令仅输出
    bar
    。转义单引号(
    \'
    )会产生相同的结果

  • 带双引号的idem:
    PATTERN=“-name bar-或-name\”*.$i\”
    ——仅返回
    bar

  • find
    命令中,如果将
    $PATTERN
    替换为
    “$PATTERN”
    ,则会出现一个错误(对于单引号,错误相同,但在通配符模式周围有单引号):

    查找:未知谓词
    -名称栏-或-name“*.a”

当然,将
$PATTERN
替换为
'$PATTERN'
也不起作用。。。(没有发生任何扩张)

我能让它工作的唯一方法就是使用<代码>评估

FINDSTR="find . \( $PATTERN \)"
eval $FINDSTR
这可以正常工作:

./zoo.a
./foo.a
./bar
在谷歌搜索了很多次之后,我看到它多次提到要做这种事情,应该使用数组。但这不起作用:

i="a"
PATTERN=( -name bar -or -name '*.$i' )
find . \( "${PATTERN[@]}" \)

# result: ./bar
find
行中,数组必须用双引号括起来,因为我们希望将其展开。但通配符表达式周围的单引号不起作用,也根本不使用引号:

i="a"
PATTERN=( -name bar -or -name *.$i )
find . \( "${PATTERN[@]}" \)

# result: find: paths must precede expression: zoo.a
但双引号确实有效

i="a"
PATTERN=( -name bar -or -name "*.$i" )
find . \( "${PATTERN[@]}" \)

# result:
# ./zoo.a
# ./foo.a
# ./bar
所以我想我的问题实际上是两个问题:

a) 在最后一个使用数组的示例中,为什么
*.$i
周围需要双引号

b) 以这种方式使用数组应该是扩展的。如何使用变量实现这一点(参见我的第一次尝试)?在实现这个功能后,我返回并再次尝试使用一个变量,使用黑色斜杠单引号,或
\\\'
,但没有任何效果(我只得到
)。我需要做什么才能模仿“手工”使用数组时的引用


提前感谢您的帮助。

必读书目:

  • -
a) 在最后一个使用数组的示例中,为什么
*.$i
周围需要双引号

您需要使用某种形式的引号来防止shell在
*
上执行全局扩展。变量不以单引号展开,因此
“*。$i”
不起作用。它确实抑制glob扩展,但也阻止变量扩展<代码>“*。$i”禁止全局扩展,但允许变量扩展,这是完美的

要真正深入了解细节,您需要在这里做两件事:

  • 转义或引用
    *
    以防止全局扩展
  • $i
    视为变量展开,但引用它以防止分词和全局展开
  • 任何形式的引用都适用于第1项:
    \*
    “*”
    “*”
    “*”
    $“*”
    都是可以接受的方式,以确保它被视为文字星号

    对于第2项,双引号是唯一的答案。裸露的
    $i
    会受到分词和全局搜索的影响——如果您有
    i='foo bar'
    i='foo*'
    ,则空格和全局搜索将导致问题
    \$i
    '$i'
    都按字面意思处理美元符号,因此它们都不存在

    “$i”
    是唯一正确的引用。这就是为什么常见的shell建议总是双引号变量展开

    最终结果是,以下任何一项都会起作用:

    "*.$i"
    \*."$i"
    '*'."$i"
    "*"."$i"
    '*.'"$i"
    
    显然,第一个是最简单的

    b) 以这种方式使用数组应该扩展«到单独引用的所有元素»。如何使用变量实现这一点(参见我的第一次尝试)?在实现这个功能后,我返回并再次尝试使用一个变量,使用黑色斜杠单引号,或
    \\\'
    ,但没有任何效果(我只得到
    )。我需要做什么才能模仿“手工”使用数组时的引用

    你必须用
    eval
    拼凑一些东西,但那很危险。从根本上说,数组比简单的字符串变量更强大。没有引号和反斜杠的神奇组合可以让你做数组能做的事情。数组是执行此任务的正确工具

    你能更详细地解释一下为什么
    PATTERN=“-name bar-或-name\”*.$i\”
    不起作用?当实际运行
    find
    命令时,带引号的双引号应展开
    $i
    ,但不展开glob

    当然。假设我们写:

    i=a
    PATTERN="-name bar -or -name \"*.$i\""
    find . \( $PATTERN \)
    
    前两行运行后,
    $PATTERN
    的值是多少?让我们检查一下:

    $ i=a
    $ PATTERN="-name bar -or -name \"*.$i\""
    $ printf '%s\n' "$PATTERN"
    -name bar -or -name "*.a"
    
    您会注意到,
    $i
    已被
    a
    替换,反斜杠已被删除

    现在让我们看看
    find
    命令是如何解析的。在最后一行中,
    $PATTERN
    是不带引号的,因为我们希望所有单词都分开,对吗?如果编写一个裸变量名,Bash将执行一个隐含的split+glob操作。它执行分词和全局扩展。这到底是什么意思

    让我们看看Bash如何执行命令行扩展。在“扩展”部分下,我们可以看到操作顺序:

  • 支架扩张
  • 瓷砖
    $ i=a
    $ PATTERN="-name bar -or -name \"*.$i\""
    $ printf '%s\n' "$PATTERN"
    -name bar -or -name "*.a"
    
    ['find . \( $PATTERN \)']
    
    ['find', '.', '\(', '$PATTERN', '\)']
    
    ['find', '.', '\(', '-name bar -or -name "*.a"', '\)']
    
    ['find', '.', '\(', '-name', 'bar', '-or', '-name', '"*.a"', '\)']
    
    ['find', '.', '\(', '-name', 'bar', '-or', '-name', '"*.a"', '\)']
    
    ['find', '.', '(', '-name', 'bar', '-or', '-name', '"*.a"', ')']
    
    $ touch 'foobar' '"foobar"'
    $ ls
    foobar   "foobar"
    $ ls foo*
    foobar
    $ ls "foo*"
    ls: foo*: No such file or directory
    $ var="\"foo*\""
    $ echo "$var"
    "foo*"
    $ ls $var
    "foobar"