bash 在循环中分配给数组索引的bash麻烦
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11942214/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
bash trouble assigning to an array index in a loop
提问by user1596414
I can get this to work in ksh but not in bash which is really driving me nuts. Hopefully it is something obvious that I'm overlooking.
我可以让它在 ksh 中工作,但不能在 bash 中工作,这真的让我发疯。希望这是我忽略的显而易见的事情。
I need to run an external command where each line of the output will be stored at an array index.
我需要运行一个外部命令,其中输出的每一行都将存储在数组索引处。
This simplified example looks like it is setting the array in the loop correctly however after the loop has completed those array assignments are gone? It's as though the loop is treated completely as an external shell?
这个简化的例子看起来像是正确地设置了循环中的数组,但是在循环完成后,那些数组分配就消失了?好像循环被完全视为外壳?
junk.txt
垃圾.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[@]}
Output
输出
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
So while in the loop, we assign array[i] and the echo verifies it. But after the loop I'm back at array[0] containing "hello" with no other elements.
因此,在循环中,我们分配 array[i] 并且回声对其进行验证。但是在循环之后,我又回到了包含“hello”而没有其他元素的数组[0]。
Same results across bash 3, 4 and different platforms.
在 bash 3、4 和不同平台上的结果相同。
回答by chepner
Because your while loop is in a pipeline, all variable assignments in the loop body are local to the subshell in which the loop is executed. (I believe kshdoes not run the command in a subshell, which is why you have the problem in bash.) Do this instead:
因为您的 while 循环在管道中,所以循环体中的所有变量赋值都是执行循环的子 shell 的本地变量。(我相信ksh不会在子 shell 中运行命令,这就是为什么你在bash. 中遇到问题的原因。)改为这样做:
while read line
do
array[i]="$line"
echo "array[$i] = ${array[i]}"
let i++
done < junk.txt
Rarely, if ever, do you want to use catto pipe a singlefile to another command; use input redirection instead.
很少,如果有的话,您想使用cat管道将单个文件传输到另一个命令吗?改用输入重定向。
UPDATE: since you need to run from a command and not a file, another option (if available) is process substitution:
更新:由于您需要从命令而不是文件运行,另一个选项(如果可用)是进程替换:
while read line; do
...
done < <( command args ... )
If process substitution is not available, you'll need to output to a temporary file and redirect input from that file.
如果进程替换不可用,您需要输出到一个临时文件并从该文件重定向输入。
If you are using bash 4.2 or later, you can execute these two commands before your loop, and the original pipe-into-the-loop will work, since the while loop is the lastcommand in the pipeline.
如果您使用的是 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
UPDATE 2: Here is a loop-less solution based on user1596414's comment
更新 2:这是一个基于 user1596414 评论的无循环解决方案
array[0]=hello
IFS=$'\n' array+=( $(command) )
The output of your command is split into words based solely on newlines (so that each line is a separate word), and appends the resulting line-per-slot array to the original. This is very nice if you are only using the loop to build the array. It can also probably be modified to accomodate a small amount of per-line processing, vaguely similar to a Python list comprehension.
您的命令的输出仅基于换行符拆分为单词(因此每一行都是一个单独的单词),并将生成的每槽行数组附加到原始数组中。如果您只使用循环来构建数组,这非常好。它也可能被修改以适应少量的每行处理,模糊地类似于 Python 列表理解。

![[] 在 bash 中做什么?](/res/img/loading.gif)