基本上,我正在使用find命令搜索存在于许多目录中的多字文件,并且输出存储在变量vari中

    vari = `find -name "multi word file.xml"


当我尝试使用for循环来删除文件时,

    for file in ${vari[@]}


执行失败说。

    rm: cannot remove `/abc/xyz/multi':: No such file or directory


你们能帮我解决这种情况吗?

最佳答案

如果您确实需要预先捕获数组中的所有文件路径(假设bash,主要是由于使用了数组和process substitution (<(...)) [1];那么符合POSIX的解决方案会比较麻烦[2];还请注意,这是基于行的解决方案,因此它无法正确处理带有嵌入式换行符的文件名,但这在实践中非常罕见):




# Read matches into array `vari` - safely: no word splitting, no
# globbing. The only caveat is that filenames with *embedded* newlines
# won't be handled correctly, but that's rarely a concern.
# bash 4+:
readarray -t vari < <(find . -name "multi word file.xml")
# bash 3:
IFS=$'\n' read -r -d '' -a vari < <(find . -name "multi word file.xml")

# Invoke `rm` with all array elements:
rm "${vari[@]}"  # !! The double quotes are crucial.



否则,让find直接执行删除操作(这些解决方案还可以正确处理带有嵌入式换行符的文件名):




find . -name "multi word file.xml" -delete

# If your `find` implementation doesn't support `-delete`:
find . -name "multi word file.xml" -exec rm {} +




至于你尝试了什么:


vari=`find -name "multi word file.xml"`(我删除了=周围的空格,这将导致语法错误)不会创建数组;这样的command substitution会将随附命令中的stdout输出作为单个字符串返回(除去尾随的换行符)。


通过将命令替换包含在( ... )中,可以创建一个数组:
vari=( `find -name "multi word file.xml"` )
但这会在find的输出上执行word splitting,并且不能正确保留带空格的文件名。
尽管可以使用IFS=$'\n'解决此问题,以便仅在行边界处进行拆分,但是生成的令牌仍受pathname expansion (globbing)约束,这可能会无意中更改文件路径。
尽管也可以使用shell选项解决此问题,但是您现在需要提前执行两项设置并恢复其原始值;因此,使用上面演示的readarrayread是更简单的选择。

即使您确实设法正确地将$vari中的文件路径收集为一个数组,也将破坏该数组为${vari[@]}-不带双引号-因为生成的字符串将再次受到单词拆分和路径名扩展的影响(球)。


要在不对其元素进行任何解释的情况下安全地将数组扩展为其元素,请双引号:"${vari[@]}"





[1]

使用进程替代而不是管道,以确保readarray / read在当前外壳而​​不是子外壳中执行。

正如eckes在注释中指出的那样,如果您尝试使用find ... | IFS=$'\n' read ...,则read将在子shell中运行,这意味着它创建的变量将在命令返回时消失(超出范围),并且无法执行。稍后使用。

[2]

POSIX Shell规范。不支持数组或进程替换(既不支持readarray,也不支持除read以外的任何-r选项);您必须按以下方式实施逐行处理:

while IFS='
' read -r vari; do
  pv vari
done <<EOF
$(find . -name "multi word file.xml")
EOF


注意,由于IFS=' syntax不可用,因此在'$'\n'之间需要实际换行符才能分配换行符。

10-08 02:33