Bash:管道“find”输出到“readarray”

vil*_*apx 18 bash find

我正在尝试使用 搜索文件find,并将这些文件放入 Bash 数组中,以便我可以对它们进行其他操作(例如lsgrep它们)。但我不明白为什么readarray不读取通过find管道输入的输出。

假设我在当前目录中有两个文件,file1.txt并且file2.txt. 所以find输出如下:

$ find . -name "file*"
./file1.txt
./file2.txt
Run Code Online (Sandbox Code Playgroud)

所以我想把它传送到一个数组中,它的两个元素是字符串"./file1.txt""./file2.txt"(显然没有引号)。

我已经尝试过这个,除此之外还有其他一些事情:

$ declare -a FILES
$ find . -name "file*" | readarray FILES
$ echo "${FILES[@]}"; echo "${#FILES[@]}"

0
Run Code Online (Sandbox Code Playgroud)

echo输出中可以看出,我的数组是空的。

那么我到底做错了什么?为什么readarray不将 readingfind的输出作为其标准输入并将这些字符串放入数组中?

cho*_*oba 26

使用管道时,bash 在子 shell 中运行命令¹。因此,该数组已填充,但位于子 shell 中,因此父 shell 无法访问它。您可能还需要该-t选项,以便不将该行分隔符存储在数组成员中,因为它们不是文件名的一部分。

使用进程替换:

readarray -t FILES < <(find .)
Run Code Online (Sandbox Code Playgroud)

请注意,它不适用于路径中带有换行符的文件。除非您可以保证不会出现这种情况,否则您希望使用 NUL 分隔的记录而不是换行分隔的记录:

readarray -td '' < <(find . -print0)
Run Code Online (Sandbox Code Playgroud)

(该-d选项是在 bash 4.4 中添加的)


¹ 使用lastpipe选项时的最后一个管道组件除外,但这仅适用于bash.

  • 为了支持换行,这就足够了:`readarray -d '' &lt; &lt;(find your_args -print0)` (3认同)

小智 7

正确的解决办法是:

unset a; declare -a a
while IFS= read -r -u3 -d $'\0' file; do
    a+=( "$file" )        # or however you want to process each file
done 3< <(find /tmp -type f -print0)
Run Code Online (Sandbox Code Playgroud)

这类似于Greg 的 BashFAQ 020详细解释的内容,该答案涵盖了.

对带有空格或换行符的奇怪命名文件(名称中不包含 NUL)没有问题。结果被设置在一个数组中,这使得它对进一步处理很有用。