我尝试用下面的方式在 bash-4.2 中初始化一个数组:
ring=()
ls -las | tail -n +4 | while read line
> do
> ring+=("$line")
> echo ${ring[-1]}
> done
3924 -rw-r--r-- 1 username group 4015716 Mar 23 15:14 script.jar
4 -rw-r--r-- 1 username group 9 Feb 29 12:40 rec.lst
5541 -rw-r--r-- 1 username group 5674226917 Mar 28 15:25 debug.out
8 -rw-r--r-- 1 username group 6135 Mar 25 12:16 script.class
8 -rw-r--r-- 1 username group 6377 Mar 25 11:57 script.java
8 -rwxr-xr-x 1 username group 4930 Mar 8 15:21 script-0.0.0.sh
8 -rwxr-xr-x 1 username group 6361 Mar 28 15:27 script-0.0.1.sh
echo ${ring[0]}
echo "${ring[0]}"
echo "${ring[@]}"
出了什么问题,为什么循环结束后我得到空数组?
答案1
您的问题是,在管道 ( command1 | command2 | command3 ...
) 中,命令在子 shell 中运行。变量不在子 shell 之间或子 shell 与主 shell 之间共享。 while 循环中的循环与主 shell 中的ring
循环不同。ring
克服这个问题的一种方法是使用进程替换:
while read line; do ring+=("$line"); echo ${ring[-1]}; done < <(ls -las|tail -n +4)
语法<(command)
称为流程替代并将命令的输出重定向到命名管道。然后将其重定向为熟悉的文件<
,就像它是一个文件一样。当您使用 时<
,没有子 shell,因此ring
将设置该变量。
请注意,有一个 shell 内置命令可以从文件的行中填充数组:
mapfile -t ring < <(ls -las | tail -n +4)
答案2
这应该可以正常工作:
ring=()
while read line
do
ring+=("$line")
echo ${ring[-1]}
done < <(ls -las | tail -n +4)
答案3
原因是 while 循环是在子 shell 中执行的,因为它是通过管道传输的。 Subshell 使用父 shell 环境的副本,并且当子 shell 退出时不会将其传回。
对于 bash,您可以使用命令分组解决方法,请注意添加了大括号
ls -las | tail -n +4 | { while read line; do ring+=("$line"); echo ${ring[-1]}; done; echo ${ring[0]}; }