2012-08-13 72 views
6

我可以得到這個在ksh中工作,但不是在bash中,這真的讓我瘋了。 希望這是明顯的,我俯瞰。bash麻煩分配給一個循環中的數組索引

我需要運行一個外部命令,其中每行的輸出將存儲在數組索引處。

這個簡化的例子看起來好像是在循環中正確地設置數組,但是在循環完成後,這些數組賦值都沒有了?就好像這個循環被完全視爲一個外殼一樣?

junk.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 

因此,儘管在循環中,我們分配陣列[i]和所述回聲進行驗證。 但循環後,我回到陣列[0]包含「你好」沒有其他元素。

bash 3,4和不同平臺上的結果相同。

回答

7

因爲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列表理解模式相似。

+0

「我需要運行一個外部命令,其中輸出的每一行都將存儲在數組索引處。」 「貓」是一個簡單的例子。我需要運行一個命令,並將其輸出到循環中,並像 user1596414 2012-08-13 21:07:10

+0

更新了幾個選項。最後一個(如果你的bash版本足夠新)可能是你想要的。 – chepner 2012-08-13 21:21:23

+1

+1臨時文件或bash 4.2(或更高版本)選項可以工作。有第三個選項使用IFS來處理空白,如果不需要遍歷輸出,也可以與簡單的數組賦值相結合。 – user1596414 2012-08-13 22:11:44