我可以让它在 ksh 中工作,但不能在 bash 中工作,这真的让我抓狂。 希望这是我忽略的显而易见的事情。
我需要运行一个外部命令,其中输出的每一行都将存储在一个数组索引中。
这个简化的示例看起来像是在循环中正确设置了数组,但是在循环完成后那些数组赋值就消失了吗?好像循环完全被当作一个外壳?
垃圾.txt
this is a
test to see
if this works ok
testa.sh
#!/bin/bash
declare -i i=0
declare -a array
echo "Simple Test:"
array[0]="hello"
echo "array[0] = ${array[0]}"
echo -e "\nLoop through junk.txt:"
cat junk.txt | while read line
do
array[i]="$line"
echo "array[$i] = ${array[i]}"
let i++
done
echo -e "\nResults:"
echo " array[0] = ${array[0]}"
echo " Total in array = ${#array[*]}"
echo "The whole array:"
echo ${array[@]}
输出
Simple Test:
array[0] = hello
Loop through junk.txt:
array[0] = this is a
array[1] = test to see
array[2] = if this works ok
Results:
array[0] = hello
Total in array = 1
The whole array:
hello
因此在循环中,我们分配 array[i] 并回显验证它。 但在循环之后,我回到了包含“hello”但没有其他元素的数组 [0]。
bash 3、4 和不同平台上的结果相同。
最佳答案
因为您的 while 循环在管道中,所以循环体中的所有变量赋值对于执行循环的子 shell 都是本地的。 (我相信 ksh
不会在子 shell 中运行该命令,这就是您在 bash
中遇到问题的原因。)改为这样做:
while read line
do
array[i]="$line"
echo "array[$i] = ${array[i]}"
let i++
done < junk.txt
您很少(如果有的话)想要使用cat
将单个 文件通过管道传输到另一个命令;请改用输入重定向。
更新:由于您需要从命令而不是文件运行,另一个选项(如果可用)是进程替换:
while read line; do
...
done < <( command args ... )
如果进程替换不可用,您将需要输出到一个临时文件并重定向来自该文件的输入。
如果您使用的是 bash 4.2 或更高版本,您可以在循环之前执行这两个命令,并且原始的管道进入循环将起作用,因为 while 循环是最后命令正在筹备中。
set +m # Turn off job control; it's probably already off in a non-interactive script
shopt -s lastpipe
cat junk.txt | while read line; do ...; done
更新 2:这是一个基于 user1596414 评论的无循环解决方案
array[0]=hello
IFS=$'\n' array+=( $(command) )
命令的输出仅根据换行符拆分为单词(因此每一行都是一个单独的单词),并将生成的每槽行数组附加到原始数组。如果您只使用循环来构建数组,这是非常好的。它也可能被修改以适应少量的每行处理,模糊地类似于 Python 列表理解。
关于arrays - bash 在循环中分配给数组索引时遇到问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56729396/