我只想将某个目录中的所有文件放入一个 bash 数组中(假设所有文件的名称中都没有换行符):
所以:
myarr=()
find . -maxdepth 1 -name "mysqldump*" | mapfile -t myarr; echo "${myarr[@]}"
Run Code Online (Sandbox Code Playgroud)
结果为空!
如果我使用临时文件或其他文件的迂回方式:
myarr=()
find . -maxdepth 1 -name "mysqldump*" > X
mapfile -t myarray < X
echo "${myarray[@]}"
Run Code Online (Sandbox Code Playgroud)
结果!
但是为什么不能mapfile
从管道中正确读取?
Kam*_*ski 27
来自man 1 bash
:
管道中的每个命令都作为单独的进程(即,在子外壳中)执行。
此类子shell 从主shell 继承变量,但它们是独立的。这意味着mapfile
在您的原始命令中自行操作myarr
。然后echo
(在管道外)打印空myarr
(这是主壳的myarr
)。
此命令的工作方式不同:
find . -maxdepth 1 -name "mysqldump*" | { mapfile -t myarr; echo "${myarr[@]}"; }
Run Code Online (Sandbox Code Playgroud)
在这种情况下,mapfile
并echo
在相同的myarr
(不是主 shell 的myarr
)上操作。
要更改主 shell,myarr
您必须mapfile
完全在主 shell 中运行。例子:
myarr=()
mapfile -t myarr < <(find . -maxdepth 1 -name "mysqldump*")
echo "${myarr[@]}"
Run Code Online (Sandbox Code Playgroud)
ilk*_*chu 11
Bash 在子 shell 环境中运行管道的命令,因此在其中发生的任何变量赋值等对 shell 的其余部分都是不可见的。
Dash(Debian 的/bin/sh
)和busybox 的sh
类似,而zsh 和ksh 在主shell 中运行最后一部分。在 Bash 中,您可以使用它shopt -s lastpipe
来执行相同的操作,但它仅在禁用作业控制时有效,因此默认情况下不能在交互式 shell 中使用。
所以:
$ bash -c 'x=a; echo b | read x; echo $x'
a
$ bash -c 'shopt -s lastpipe; x=a; echo b | read x; echo $x'
b
Run Code Online (Sandbox Code Playgroud)
(read
并且mapfile
有同样的问题。)
或者(正如Attie所提到的),使用进程替换,它的工作方式类似于通用管道,并在 Bash、ksh 和 zsh 中受支持。
$ bash -c 'x=a; read x < <(echo b); echo $x'
b
Run Code Online (Sandbox Code Playgroud)
POSIX 未指定管道的部分是否在子外壳中运行,因此不能真正说任何外壳在这方面都是“错误的”。
正如 Kamil 所指出的,管道中的每个元素都是一个单独的过程。
您可以使用以下流程替换来find
在不同的流程中运行,mapfile
调用保留在您当前的解释器中,允许myarr
之后访问:
myarr=()
mapfile -t myarr < <( find . -maxdepth 1 -name "mysqldump*" )
echo "${myarr[@]}"
Run Code Online (Sandbox Code Playgroud)
b < <( a )
将类似于a | b
管道的接线方式 - 不同之处在于b
在“此处”执行。