2015-09-12 3 views
0

Я не уверен, что происходит здесьПочему я не могу добавить массив?

#!/bin/bash 

STRING_PREFIX="foo" 
STRING_IDX="1,2,3,4,5" 

declare -a STRING_ARRAY 

main() { 
    assemble_strings 

    for i in "${STRING_ARRAY[@]}"; do 
    echo "TEST: $i" 
    done 
} 

assemble_strings() { 
    IFS=, 
    while IFS= read idx; do 
    STRING_ARRAY+=("${STRING_PREFIX}${idx}") 
    done < <(echo $STRING_IDX)  
} 

main 

Я ожидаю, что массив из 5 строк, каждая предваряется «Foo». Вместо этого я получаю массив из 1 строки

TEST: foo1 2 3 4 5 

Для получения бонусных очков, как я могу полностью избежать цикла? Я не могу понять, как создать массив из выражения в bash.

+1

'echo $ STRING_IDX' испускает только одну строку, обрабатываемую одним вызовом' read'. Почему вы ожидаете, что это будет больше? –

+0

BTW, используя имена всех шапок для ваших собственных переменных - плохая форма; эти имена зарезервированы по соглашению, чтобы по ошибке не переписывать переменные, зависящие от системы или оболочки. См. Четвертый абзац http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html, имея в виду, что переменные оболочки и переменные среды совместно используют одно пространство имен. –

+0

Кстати, если ваш контент был отделен символами новой строки, а не запятыми, я бы предложил использовать функцию bash 4 'readarray' (также известную по ее синониму,' mapfile'). –

ответ

3

Первое: Потому что вы положили IFS= на передней панели read, предшествующий IFS=, ничего не делает (поскольку этот read обеспокоен).

Во-вторых: поскольку вы не устанавливаете -d , в свой read, он использует значение по умолчанию - значение новой строки в качестве терминатора записи. (IFS определяет поле , а не запись терминатор с пустым значением IFS, ваши записи имеют только одно поле в них). Таким образом, когда вы вызываете read, он считывает всю запись - до новой строки - так что ваш цикл запускается только один раз.


Один из подходов, с помощью read -a для чтения непосредственно в массив (в данном случае, рассматривая весь входной поток в виде одной записи, с полями, разделенными запятыми):

string_idx=1,2,3,4,5 
string_prefix=foo 

# use read to directly populate the array 
IFS=, read -r -d '' -a string_array <<<"$string_idx" 

# go back through and tack on prefixes 
for idx in "${!string_array[@]}"; do 
    string_array[$idx]="${string_prefix}${string_array[$idx]}" 
done 

# print values 
printf ' entry: %s\n' "${string_array[@]}" 

Другое, внесение наименьшего изменения в ваш существующий код - обработка входного потока в виде серии однофазных записей, разделенных запятыми:

string_idx=1,2,3,4,5 
string_prefix=foo 
string_array=() 

while IFS= read -r -d , idx; do 
    string_array+=("${string_prefix}${idx}") 
done <<<"$string_idx," 
+0

Да, 'printf' и bash массивы идут вместе, как масло и хлеб. – bishop

+0

Спасибо! Что касается цикла while. Я читал о замещении процесса другой ночью, и я думаю, что я был слишком возбужден :) – vicTROLLA

+0

Хех. Использование цикла 'while read', безусловно, является хорошей практикой во многих ситуациях; он находится в ядре BashFAQ # 1 (http://mywiki.wooledge.org/BashFAQ/001). –