Читання відмежованого рядка в масив у Bash


206

У мене є змінна, яка містить рядок, обмежений пробілом:

line="1 1.50 string"

Я хочу розділити цей рядок на простір як роздільник і зберегти результат у масиві, щоб наступне:

echo ${arr[0]}
echo ${arr[1]}
echo ${arr[2]}

виходи

1
1.50
string

Десь я знайшов рішення, яке не працює:

arr=$(echo ${line})

Якщо після цього я запускаю заяви ехо вище, я отримую:

1 1.50 string
[empty line]
[empty line]

Я також спробував

IFS=" "
arr=$(echo ${line})

з тим же результатом. Може хтось допоможе, будь ласка?


Дивіться цю відповідь на Unix & Linux Stack Exchange: Використання sed з herestring (<<<) та read -a . set -f; arr=($string); set +fздається, швидше, ніж read -r -a <<< $string.
кодове літо

Відповіді:


331

Для того, щоб перетворити рядок у масив, будь ласка, використовуйте

arr=($line)

або

read -a arr <<< $line

Дуже важливо не використовувати лапки, оскільки це робить фокус.


7
і зробити санітарну перевірку вашого прекрасного нового масиву:for i in ${arr[@]}; do echo $i; done
Банджер

5
або простоecho ${arr[@]}
Банджер

13
Обидва способи можуть вийти з ладу, якщо $lineв ньому є символи глобалізації. mkdir x && cd x && touch A B C && line="*" arr=($line); echo ${#arr[@]}дає 3
Тіно

3
declare -a "arr=($line)"буде ігнорувати IFSроздільники всередині цитованих рядків
Дейв

4
@Tino Ні. Коли line='*', read -a arr <<<$lineзавжди працюйте, але тільки arr=($line)не вдається.
Джонні Вонг

39

Спробуйте це:

arr=(`echo ${line}`);

5
Приємно. Це рішення також працює в оболонці Z, де деякі інші підходи, наведені вище, не спрацьовують.
Кіт Хугітт

Це працює, ви можете, будь ласка, пояснити, чому це працює?
smartwjw

2
Зауваження: це не працює ні тоді, коли в рядку є "*", наприкладline='*'
Johnny Wong

34

В: arr=( $line ). "Розкол" пов'язується з "глобусом".
Символи узагальнення ( *, ?і []) будуть розширені до відповідності імен файлів.

Правильне рішення лише трохи складніше:

IFS=' ' read -a arr <<< "$line"

Немає глобальної проблеми; символ розділення задається $IFS, цитуються змінні.


5
Це має бути прийнятою відповіддю. Заява arr=($line)у прийнятій відповіді страждає від глобальних питань. Наприклад, спробуйте: line="twinkling *"; arr=($line); declare -p arr.
кодове літо

Цитування необов’язкове для герестрингу, <<<але може бути хорошою ідеєю все ж використовувати подвійні лапки для послідовності та читабельності.
кодове літо

6

Якщо вам потрібно розширення параметрів, то спробуйте:

eval "arr=($line)"

Наприклад, візьміть наступний код.

line='a b "c d" "*" *'
eval "arr=($line)"
for s in "${arr[@]}"; do 
    echo "$s"
done

Якщо в поточному каталозі містилися файли a.txt, b.txtа c.txtпотім виконання коду дало б такий результат.

a
b
c d
*
a.txt
b.txt
c.txt

-9
line="1 1.50 string"

arr=$( $line | tr " " "\n")

for x in $arr
do
echo "> [$x]"
done

Цикл циклічно неправильний, він розбиває масив добре, і труба trє зайвою, але "${arr[@]}"замість цього вона повинна перекидатися, а не$arr
Zorf
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.