Разбор строки с разделителями в массив в Bash - почему "$var" отличается от $ var, хотя $ var не имеет пробелов?
Я использую Bash версии 4.2.25. Вот мой код:
#!/usr/bin/env bash
string="one:two:three:four"
# without quotes
IFS=: read -ra array_1 <<< $string
for i in "${array_1[@]}"; do printf "i = [$i]\n"; done
# output:
# i = [one two three four]
# with quotes
IFS=: read -ra array_2 <<< "$string"
for i in "${array_2[@]}"; do printf "i = [$i]\n"; done
# output:
# i = [one]
# i = [two]
# i = [three]
# i = [four]
Чем объясняется разница в поведении?
2 ответа
Я не могу воспроизвести вашу проблему в Linux с bash 4.2.46 и bash 4.3.30. Однако вот адаптированная версия, которая показывает описанное поведение:
string="one:two:three:four"
IFS=:
read -ra array_1 <<< $string
for i in "${array_1[@]}"; do printf "i = [$i]\n"; done
# i = [one two three four]
read -ra array_2 <<< "$string"
for i in "${array_2[@]}"; do printf "i = [$i]\n"; done
# i = [one]
# i = [two]
# i = [three]
# i = [four]
Это происходит потому, что переменные на самом деле не делятся на пробелы, они делятся на $IFS
(по умолчанию пробел, табуляция и перевод строки).
Так как мы переопределены $IFS
, это значения с двоеточиями, мы должны быть осторожны при цитировании. Пространства больше не имеют значения.
Исходный код показывает, что Bash жестко кодирует пробел в string_list
вызывается через write_here_string. когда IFS
без пробела, строка, которая расширяется до нескольких слов, больше не будет read
в жетоны по аналогичным линиям, делая разницу более заметной.
PS: Это хороший пример того, почему мы всегда должны заключать в кавычки наши переменные, даже когда мы знаем, что они содержат.
Это похоже на ошибку. Я оглянулся CHANGES
и не смог найти ничего конкретного, но в cygwin bash 4.3.48(8), оба в кавычках и без кавычек дают ожидаемый результат (четыре строки). Иногда, когда у меня есть пропускная способность для записи, я клонирую репозиторий и обвиняю redir.c, чтобы посмотреть, смогу ли я найти какие-то соответствующие коммиты.