bash: IFS завис после временного изменения для построения массива

Я столкнулся со странной проблемой после временного изменения IFS с целью построения массива:

$ echo "1 2 3" |while read myVar1 myVar2; do echo "myVar1: ${myVar1}"; echo "myVar2: ${myVar2}"; done
myVar1: 1
myVar2: 2 3
$ IFS=':' myPaths=( ${PATH} )  # this works: I have /home/morgwai/bin on ${myPaths[0]} , /usr/local/sbin on ${myPaths[1]} and so on
$ echo "1 2 3" |while read myVar1 myVar2; do echo "myVar1: ${myVar1}"; echo "myVar2: ${myVar2}"; done
myVar1: 1 2 3
myVar2: 
$ echo $IFS

$ echo "1:2:3" |while read myVar1 myVar2; do echo "myVar1: ${myVar1}"; echo "myVar2: ${myVar2}"; done ;
myVar1: 1
myVar2: 2:3

Обычно, когда я временно меняю IFS для любой другой команды, кроме построения массива (например, IFS=',' echo whatever), его значение изменяется только во время выполнения этого, однако здесь кажется, что IFS навсегда изменился на двоеточие (хотя echo $IFS этого не показывает , что еще более странно ...).

Это ошибка или какое-то ожидаемое поведение, которого я не понимаю?
Я использую bash версии 4.4.18, если это важно ...

Примечание: я знаю, что могу построить тот же массив, используя IFS=':' read -a myPaths <<< ${PATH}, а затем IFS обычно возвращается к значению по умолчанию, но дело не в этом: я пытаюсь понять, что на самом деле происходит в приведенном выше примере. < / em>

Спасибо!


person morgwai    schedule 11.07.2020    source источник
comment
Вы просто устанавливаете переменные, а не устанавливаете переменную с последующим выполнением команды.   -  person Shawn    schedule 12.07.2020
comment
@Shawn, это действительно объясняет, почему изменение кажется постоянным, но почему echo $IFS показывает пустую строку вместо двоеточия?   -  person morgwai    schedule 12.07.2020
comment
Кстати, я бы предложил printf '%q\n' "$IFS" отображать текущее значение в визуально однозначной форме.   -  person Charles Duffy    schedule 12.07.2020
comment
... но да, в случае IFS=':' myPaths=( ${PATH} ) это всего два назначения, и ни одно из них не является временным; в строке должна быть настоящая обычная команда, чтобы предшествующие им назначения обрабатывались как переменные среды, привязанные к этой команде.   -  person Charles Duffy    schedule 12.07.2020
comment
Кстати, array=( $content ) не является хорошей практикой - если вы не отключите глобализацию, у нее есть потенциал для большего, чем просто разбиение на IFS. См. BashPitfalls # 50.   -  person Charles Duffy    schedule 12.07.2020
comment
@CharlesDuffy способ, которым вы редактировали мой вопрос, существенно меняет его: я не устанавливаю IFS в кому в начале, как вы это делаете в своем редактировании, и echo $IFS печатает пустую строку, что является важным фактором, и я надеюсь получить объяснение также   -  person morgwai    schedule 12.07.2020
comment
@Shawn Я нашел объяснение пустой строки на echo $IFS, это довольно забавно;) ubuntuforums.org/showthread .php? t = 1454313   -  person morgwai    schedule 12.07.2020
comment
Кстати, современный bash позволяет использовать ${IFS@E} или ${IFS@Q} вместо этого printf бита.   -  person Shawn    schedule 12.07.2020
comment
Попался. Я попытался отредактировать, чтобы прояснить, но, очевидно, не понял, о чем вы пытались спросить. (Что действительно согласуется с идеей о необходимости разъяснения).   -  person Charles Duffy    schedule 12.07.2020
comment
(re: установка запятой в начале, это должно было иметь известное значение, чтобы мы могли сравнивать с этим известным значением позже; в исходном вопросе не было определено, каким должно быть значение IFS).   -  person Charles Duffy    schedule 12.07.2020
comment
Вот хорошая статья по теме: IFS   -  person M. Nejat Aydin    schedule 12.07.2020
comment
@CharlesDuffy: да, в итоге оказалось, что это две отдельные проблемы, но сначала я думал, что они тесно связаны, отсюда и путаница: извините за это. В любом случае, спасибо за ваш вклад и готовность помочь :)   -  person morgwai    schedule 12.07.2020


Ответы (1)


Вы просто устанавливаете переменные, а не устанавливаете переменную, за которой следует выполнение команды (т. Е. Способ построения массива - это чистое присвоение переменной, а не команда, поэтому оба присваивания становятся постоянными).

Проблема с IFS из :, не отображаемым в echo $IFS, вызвана расширением параметров оболочки и разделением слов.

Рассмотреть возможность:

$ IFS=:
$ echo $IFS

$ echo "$IFS"
:

Если расширение параметра не заключено в кавычки, оно подвергается разделению слов после слов. Из руководства:

Оболочка просматривает результаты раскрытия параметров, подстановки команд и арифметических операций, которые не были заключены в двойные кавычки, на предмет разбиения слов.

а также

Оболочка обрабатывает каждый символ $IFS как разделитель и разбивает результаты других расширений на слова, используя эти символы в качестве ограничителей полей. Если IFS не задан или его значение равно <space><tab><newline>, по умолчанию, то последовательности <space>, <tab> и <newline> в начале и конце результатов предыдущих расширений игнорируются, а любая последовательность символов IFS не в начале или конец служит для разграничения слов.

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

person Shawn    schedule 12.07.2020
comment
Ах. Это сделало бы вопрос дубликатом Я просто присвоена переменная, но echo $variable выводит что-то еще. - person Charles Duffy; 12.07.2020
comment
это именно то, что написано в ссылке на ubuntuforums, которую я отправил ранее;) (ubuntuforums.org /showthread.php?t=1454313 последний пост, нужно прокрутить вниз). Я поддерживаю ваш ответ в знак признания вашего первого первоначального комментария к вопросу, который, хотя и очень прост, содержал ответ на основную проблему. Если вы хотите поместить его в начало своего ответа, я также отмечу его как принятый (в его нынешней форме ответ не отвечает на главный вопрос, поэтому другим будет сложно увидеть его принятым). - person morgwai; 12.07.2020