Bash строка в массив с IFS

У меня возникли проблемы с использованием IFS для преобразования моей строки в массив. Вот что я имею в качестве строки:

"Jun01 Jun02 Jun03 Jun04 Jun05 ..." #in that format, separated by spaces

И вот код, который я пробовал:

IFS=" " #set it to space character
DATES_ARRAY=($DATES_STRING) #from above
echo ${DATES_ARRAY[0]} #output is empty

Однако, когда я удаляю строку IFS, она работает. Но я использовал несколько строк, чтобы распечатать его значение по умолчанию ASCII, и я получил "32", что означает "пробел". Будучи программистом OCD, я хотел бы сам настроить его, чтобы быть в безопасности... Я не знаю, как это будет предустановлено априори!

Итак, почему попытка установить IFS в Space вручную не работает?

Ответ 1

Это действительно работает, но в любом случае это необязательно, потому что по умолчанию гарантируется, что пространство будет в IFS. Не устанавливайте его вручную. Это может вызвать проблемы.

В принципе, никогда не используйте разбиение слов в Bash. Иногда это требовало укусить пулю и использовать ее, если она ограничена POSIX sh, если ее использовать очень осторожно. Если вы собираетесь установить IFS, установите его в среде одной из немногих команд, где он имеет некоторый эффект или, самое большее, локально для функции.

Вам никогда не понадобится использовать это, поэтому я не буду все объяснять:

$ printf -v str '%s ' Jun{01..10}
$ set -f
$ IFS=' ' declare -a 'arr=($str)'
$ declare -p arr
declare -a arr='([0]="Jun01" [1]="Jun02" [2]="Jun03" [3]="Jun04" [4]="Jun05" [5]="Jun06" [6]="Jun07" [7]="Jun08" [8]="Jun09" [9]="Jun10")'

IFS установлен в пространство здесь избыточно, чтобы показать, что он работает.

Вероятно, самый правильный способ перейти от строки к массиву - использовать read. Много примеров здесь.

Каннонический метод:

read -ra arr <<<"$str"

где IFS необязательно устанавливается в среде read, чтобы действовать как разделитель, если это нечто иное, чем пробелы.

Ответ 2

Я предлагаю не использовать $IFS самостоятельно для разделения слов в массив, поскольку установка и возврат $IFS - это боль. Используйте что-то вроде этого:

DATES_STRING='Jun01 Jun02 Jun03 Jun04 Jun05'

IFS=' ' read -a DATES_ARRAY <<< "$DATES_STRING"

Я также предлагаю явно установить $IFS в среде read, чтобы вы были абсолютно уверены, что это такое.

Ответ 3

По умолчанию $IFS следует использовать пробел в качестве разделителя маркеров, включая вкладки и символы новой строки.

Попробуйте следующее:

echo "$IFS" | cat -vte

Если вы не изменили $IFS, вывод должен быть:

 ^I$
$

Это пробел, за которым следует одна вкладка: ^I и новая строка - обратите внимание, что cat печатает любые символы новой строки как $.

И поэтому ваш отрывок script должен работать, не касаясь $IFS.