我想遍历一个文件列表。这个列表是一个find命令的结果,所以我想出了:

getlist() {
  for f in $(find . -iname "foo*")
  do
    echo "File found: $f"
    # do something useful
  done
}

这很好,除非文件名称中有空格:

$ ls
foo_bar_baz.txt
foo bar baz.txt

$ getlist
File found: foo_bar_baz.txt
File found: foo
File found: bar
File found: baz.txt

我能做些什么来避免空格分割?


当前回答

我最近不得不处理一个类似的情况,我构建了一个FILES数组来遍历文件名:

eval FILES=($(find . -iname "foo*" -printf '"%p" '))

这里的想法是用双引号包围每个文件名,用空格分隔它们,并使用结果初始化FILES数组。 必须使用eval来正确计算find输出中的双引号,以初始化数组。

要遍历文件,只需执行:

for f in "${FILES[@]}"; do
    # Do something with $f
done

其他回答

find . -name "fo*" -print0 | xargs -0 ls -l

见xargs先生。

在某些情况下,如果您只需要复制或移动一个文件列表,您也可以将该列表管道到awk。 重要的是$0字段周围的\"" "" \"(简而言之,您的文件,一行列表=一个文件)。

find . -iname "foo*" | awk '{print "mv \""$0"\" ./MyDir2" | "sh" }'

你可以用基于行的迭代替换基于单词的迭代:

find . -iname "foo*" | while read f
do
    # ... loop body
done

因为你没有使用find做任何其他类型的过滤,你可以使用以下bash 4.0:

shopt -s globstar
getlist() {
    for f in **/foo*
    do
        echo "File found: $f"
        # do something useful
    done
}

**/将匹配零个或多个目录,因此完整模式将匹配当前目录或任何子目录中的foo*。

好的,这是我在Stack Overflow上的第一篇文章!

Though my problems with this have always been in csh not bash the solution I present will, I'm sure, work in both. The issue is with the shell's interpretation of the "ls" returns. We can remove "ls" from the problem by simply using the shell expansion of the * wildcard - but this gives a "no match" error if there are no files in the current (or specified folder) - to get around this we simply extend the expansion to include dot-files thus: * .* - this will always yield results since the files . and .. will always be present. So in csh we can use this construct ...

foreach file (* .*)
   echo $file
end

如果你想过滤掉标准的点文件,那很简单…

foreach file (* .*)
   if ("$file" == .) continue
   if ("file" == ..) continue
   echo $file
end

在这个线程的第一篇文章中的代码将这样写:-

getlist() {
  for f in $(* .*)
  do
    echo "File found: $f"
    # do something useful
  done
}

希望这能有所帮助!