В начале сценария оболочки bash находится следующая строка:
IFS=$'\n'
В чем смысл этой коллекции символов?
IFS=$'\n'
является bashism (+ другие оболочки, использовать ANSI-C Цитирование , для обхода см stackoverflow.com/questions/10748703/...
В начале сценария оболочки bash находится следующая строка:
IFS=$'\n'
В чем смысл этой коллекции символов?
IFS=$'\n'
является bashism (+ другие оболочки, использовать ANSI-C Цитирование , для обхода см stackoverflow.com/questions/10748703/...
Ответы:
IFS
расшифровывается как «внутренний разделитель полей». Он используется оболочкой для определения того, как выполнять разбиение слов, то есть как распознавать границы слов.
Попробуйте это в оболочке, такой как bash (другие оболочки могут обрабатывать это по-разному, например, zsh):
mystring="foo:bar baz rab"
for word in $mystring; do
echo "Word: $word"
done
Значение по умолчанию для IFS
состоит из пробельных символов (если быть точным: пробел, табуляция и новая строка). Каждый символ может быть границей слова. Таким образом, со значением по умолчанию IFS
, цикл выше напечатает:
Word: foo:bar
Word: baz
Word: rab
Другими словами, оболочка считает, что пробел является границей слова.
Теперь попробуйте установить IFS=:
перед выполнением цикла. На этот раз результат:
Word: foo
Word: bar baz rab
Теперь оболочка также разбивается mystring
на слова - но теперь она рассматривает только двоеточие как границу слова.
Первый символ IFS
- специальный: он используется для разделения слов в выводе при использовании специальной $*
переменной (пример взят из Руководства по расширенному написанию сценариев Bash , где вы также можете найти дополнительную информацию о специальных переменных, подобных этой):
$ bash -c 'set w x y z; IFS=":-;"; echo "$*"'
w:x:y:z
По сравнению с:
$ bash -c 'set w x y z; IFS="-:;"; echo "$*"'
w-x-y-z
Обратите внимание , что в обоих примерах, оболочка будет по- прежнему относиться все символы :
, -
а ;
также границы слов. Единственное, что меняется, это поведение $*
.
Еще одна важная вещь, которую нужно знать, это то, как обрабатываются так называемые «пробелы IFS» . По сути, как только IFS
включаются пробельные символы, начальные и конечные пробельные символы удаляются из строки, которая должна быть разделена перед обработкой, а также последовательность последовательных пробельных символов также разделяет поля. Однако это относится только к тем пробельным символам, которые фактически присутствуют в IFS
.
Например, давайте посмотрим на строку "a:b:: c d "
(завершающий пробел и два пробела между символами c
и d
).
IFS=:
он будет разделен на четыре поля: "a"
, "b"
, ""
(пустая строка) и " c d "
(опять же , два пространства между c
и d
). Обратите внимание на начальные и конечные пробелы в последнем поле.IFS=' :'
, она будет разделена на пять полей: "a"
, "b"
, ""
(пустая строка), "c"
и "d"
. Нет ни одного начального и конечного пробела.Обратите внимание, что во втором примере несколько последовательных пробельных символов разделяют два поля, а несколько последовательных двоеточий - нет (поскольку они не являются пробельными символами).
Что же касается IFS=$'\n'
, то есть ksh93
синтаксис также поддерживается bash
, zsh
, mksh
и FreeBSD sh
(с вариациями между всеми оболочками). Цитирую man-страницу bash:
Слова вида $ 'string' обрабатываются специально. Слово расширяется до «строки», символы с обратной косой чертой заменяются в соответствии со стандартом ANSI C.
\n
является escape-последовательностью для новой строки, поэтому в IFS
конечном итоге устанавливается один символ новой строки.
bash
руководство по написанию сценариев или что-то еще. В основном, информация, доступная по таким ссылкам, не хватает важными способами. Во всяком случае, таким образом, упускается два важных момента, касающихся расщепления оболочки - глобализация и пропуски IFS.
unset IFS
оболочка ведет себя совсем иначе, чем IFS=
. Кроме того, первый байт в IFS также особенный, "${named_array[*]}"
но не имеет значения, когда расширение не
$IFS
- одна из двух основных вещей, выполняемых при раскрытии переменной без кавычек в контексте списка (это split
часть split+glob
оператора). Другой болтается. При использовании разделения работы, как правило, необходимо set -f
отключить эту glob
часть.
$IFS
также используется read
встроенной командой
Внутри долларовых одинарных кавычек некоторые символы оцениваются специально. Например, \n
переводится на новую строку.
Таким образом, эта конкретная строка присваивает новую строку переменной IFS. IFS, в свою очередь, является специальной переменной в bash: Разделитель внутренних полей. Как man bash
говорится, это
используется для разделения слов после раскрытия и разделения строк на слова с помощью
read
встроенной команды. Значением по умолчанию является<space><tab><newline>
.
dollared single quotes
которое отличается от простых одинарных кавычек.
Для краткости, IFS=$'\n'
присвойте новую строку \n
переменной IFS
.
$'string'
Конструкция - это механизм цитирования, который используется для декодирования ANSI C, как escape-последовательности. Этот синтаксис исходит от ksh93
, и был портативным современной оболочке , как bash
, zsh
, pdksh
, busybox sh
.
Этот синтаксис не определен POSIX, но был принят для выпуска SUS 7 .
Я предпочел объяснить $IFS
на примере:
если вы хотите, чтобы cp, mv или другой файл обрабатывались, IFS пуст по умолчанию, когда ваши файлы имеют метасимвол или пробел, например:
Linux Administration.pdf
или Free Software Fundation.ogg
, конечно, у вас будет проблема, потому что: Linux рассматривает отдельный параметр и Администрация рассматривают отдельный параметр. Итак, bash имеет built-in variable
, затем вы можете инициализировать IFS==$(echo -en "\n\b")
, затем bash отбрасывает любой метасимвол и пробел между именем файла, например:
#!/bin/bash
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
mymusicdir=~/test/dd
find $mymusicdir -name "*" -execdir rename 's/ /_/g' "{}" +
IFS=$SAVEIFS