Разбор строки с разделителями в массив в 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]

Чем объясняется разница в поведении?


person codeforester    schedule 10.01.2017    source источник


Ответы (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: Это хороший пример того, почему мы всегда должны цитировать наши переменные, даже если мы знаем, что они содержат.

person that other guy    schedule 10.01.2017

Это похоже на ошибку. Я просмотрел CHANGES и не смог найти ничего конкретного , но в cygwin bash 4.3.48(8) как в кавычках, так и без кавычек выдается ожидаемый результат (четыре строки). Когда-нибудь, когда у меня будет пропускная способность, я клонирую репозиторий и обвиню redir.c, чтобы посмотреть, смогу ли я найти соответствующие коммиты.

person cxw    schedule 10.01.2017
comment
Это действительно ошибка, которая была частично устранена в версии 4.3 и завершена(?) в версии 4.4. - person chepner; 10.01.2017