временное изменение IFS перед циклом for [дубликат]

Aug 16 2020

Я знаю, что SHELLпозволяет присваивать переменные непосредственно перед командой, так что IFS=":" read a b c d <<< "$here_string"работает ...

Мне было интересно, не работают ли такие назначения, когда они выполняются с помощью составных операторов, таких как циклы? Я пробовал что-то вроде, IFS=":" for i in $PATH; do echo $i; doneно это привело к синтаксической ошибке. Я всегда мог сделать что-то подобное oldIFS="$IFS"; IFS=":"; for....; IFS="$oldIFS", но я хотел знать, есть ли способ заставить такие встроенные назначения работать для составных операторов, таких как forциклы?

Ответы

3 Quasímodo Aug 16 2020 at 21:12

forявляется зарезервированным словом и поэтому следует особым правилам :

Следующие слова признаются зарезервированными:

! {} case do done elif else esac fi for if in then до while

Это распознавание должно происходить только тогда, когда ни один из символов не цитируется и когда слово используется как:

  • Первое слово команды

  • Первое слово, следующее за одним из зарезервированных слов, кроме case , for или in

  • Третье слово в команде случае (только в действительно в данном случае)

  • Третье слово в команде for ( в этом случае допустимы только in и do )

Если вы пытаетесь

IFS=":" for i in $PATH; do echo $i; done

по приведенным выше правилам это не forцикл, так как ключевое слово не является первым словом команды. Но ваше намерение может быть достигнуто с помощью

IFS=: printf '%s\n' $PATH

$PATHподвергается разделению слов, :как ожидалось, и каждое полученное слово печатается с printfпоследующим переводом строки.


Возможно, вы знакомы с этим подходом:

while IFS= read -r line; do

whileэто первое слово команды, и IFSприсвоение применяется к read, так что все в порядке.