因此,我希望将输出放入unzip -Z1
数组中,然后找到了这个答案;他们的第一个选择,使用mapfile
输入重定向和进程替换,非常有效。
但后来我想,“等等,进程替换”,它会从 stdout 创建一个文件描述符,“然后使用输入重定向将内容放入 stdin?”
这不就等同于管道吗?
显然不是。不是的。在这里我尝试将的内容放入ls
变量中,但使用管道:ls | mapfile -t test
没什么。
但是,如果我按照这个答案来回答:id estmapfile -t test < <(ls)
瞧。
我什么也没找到天生特殊关于< <()
,除了创建一个文件描述符之外。以此为理论,我尝试了 HEREDOC,它也会创建一个文件描述符。它起作用了:
mapfile -t test2 << END && printf '%s ' "${test2[@]}"
this
is
an
array
END
stdin
但如果通过via进行清洗则不行cat
,请尝试:
cat << END | mapfile -t test3 && printf '%s ' "${test3[@]}"
this
is
an
array
END
那么,我的问题是。HEREDOC
发现/文件描述符理论不应该对它有影响,mapfile
因为它的手册都说它使用“标准输入”,对吗?
如果“标准输入”在某种程度上意味着它必须是一个更花哨的描述符;为什么?为什么它不能使用简单的一次读取输入流来生成数组?
最后,如果这两个问题都得到了回答/在正确的轨道上,为什么命令在预期 fd 时没有失败?你会看到我的终端0
打印了一堆(我们&&
在最后的例子中使用),那是$?
在我的prompt
,所以内置没有报告错误。
我在 Fedora 30 和 RHEL 6 上尝试过这个,所以我不认为这是一个错误。
答案1
它确实有效;但结果随后会立即消失。
不同之处在于,这foo | mapfile
是一个由两个新进程组成的管道——每个元素(无论是外部程序还是 shell 内置程序)都在子 shell 中运行。因此,尽管 mapfile 仍可执行其工作,但它无法将结果传输到父 shell 进程。
为了进行比较,使用(mapfile < foo.txt)
或ls | while read line; do ... done
甚至都会得到相同的结果(foo=bar); echo $foo
。在所有这些情况下,如果比较 $BASHPID 和 $$,您将看到不同的值 - 前者显示子 shell 进程 PID 与主 shell PID 不同。
使用重定向时,mapfile
命令在主 shell 进程中运行,并且可以正确更改 shell 变量。它不太关心它是从真实文件、<<
生成的临时文件还是<()
生成的魔法文件进行重定向 - 在这种情况下,shell 将其作为单独的步骤处理,并且不会导致构建管道。(<()
或的内部命令$()
是当然是一个子壳。)
请注意,该变量实际上可以在子 shell 中使用 - 只是不能向上传输。因此对于一次性操作,管道的第二部分可能非常复杂:
unzip -l | {
mapfile -t test
for file in "${test[@]}"; do
echo "I got $file!"
done
}
zipinfo | while read -r file; do
echo "I got $file!"
done