Яке значення IFS = $ '\ n' у сценаріїх bash?


163

На початку сценарію оболонки bash є наступний рядок:

IFS=$'\n'

Яке значення стоїть за цією колекцією символів?


3
Дивіться також unix.stackexchange.com/questions/26784/understanding-ifs та питання, які він цитує.
Жиль

синтаксис vim виділяє це як помилку для мене; виправити?
theonlygusti

IFS=$'\n'є bashism (+ інші оболонки, використовувати ANSI-C Цитування , для обходу см stackoverflow.com/questions/10748703 / ...
pevik

Відповіді:


199

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 -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).

  1. З IFS=:він буде розділений на чотири поля: "a", "b", ""(порожній рядок) і " c d "(знову ж , два простору між cі d). Зверніть увагу на провідну та кінцеву пробіли в останньому полі.
  2. З IFS=' :', вона буде розділена на п'ять полів: "a", "b", ""(порожній рядок), "c"і "d". Ніде немає провідних і задніх пробілів.

Зверніть увагу, як кілька послідовних символів пробілів розмежовують два поля у другому прикладі, тоді як декілька послідовних кольорів - це не символи (оскільки вони не є символами пробілу).

Що ж стосується IFS=$'\n', тобто ksh93синтаксис також підтримується bash, zsh, mkshі FreeBSD sh(з варіаціями між усіма оболонками). Цитування баш-сторінки:

Слова форми $ 'string "обробляються спеціально. Слово розширюється на "рядок", при цьому символи, що ухиляються від косої риски, замінюються, як визначено стандартом ANSI C.

\nє послідовністю відходу для нового рядка, тому в IFSкінцевому підсумку встановлюється один символ нового рядка.


3
Це добре, але, на мою думку, ви б набагато краще прочитали та зрозуміли специфікацію POSIX, а не інструкцію з bashнаписання сценаріїв чи будь-що інше. В основному, інформації, доступної за такими посиланнями, бракує важливих способів. У будь-якому випадку, таким чином, не вистачає двох найважливіших моментів, що стосуються розщеплення оболонок - глобулювання та пробіл IFS.
mikeserv

@mikeserv Спасибі, я додав інформацію про пробіли IFS. Не знав про це. :)
Tblue

4
Не так актуальна, але якщо вам цікаво, ви можете захотіти поглянути на те, як unset IFSробить оболонка поводиться зовсім інакше , ніж IFS=. Також перший байт в IFS також є спеціальним "${named_array[*]}", але не має значення, коли розширення не
котирується

Ще кілька моментів: розділення слів, яким керує, $IFSє однією з двох головних речей, що виконуються при розширенні нецитованої змінної в контексті списку (це splitчастина split+globоператора). Інший - глобус. Під час використання розбивки на роботу, як правило, потрібно видалити, set -fщоб вимкнути globдеталь.
Стефан Шазелас

3
3- $IFSтакож використовується readвбудованою командою
Стефан Шазелас

22

Всередині одинарних цитат, що знаходяться в доларі, деякі символи оцінюються спеціально. Наприклад, \nпереведений на новий рядок.

Отже, саме цей рядок присвоює нову рядок змінній IFS. IFS, у свою чергу, є спеціальною змінною в bash: Internal Field Separator. Як man bashкажуть, це

використовується для розбиття слів після розширення та для розділення рядків на слова за допомогою readвбудованої команди. Значенням за замовчуванням є <space><tab><newline>.


5
+1 для згадки, dollared single quotesщо відрізняється від простих одиничних цитат.
Snowcrash

2
@Snowcrash +1 для того, щоб сказати +1, щоб згадати про одиночні цитати з долар, що відрізняється від простих одиничних цитат . Вибачте, я не міг допомогти йому :) Але насправді це дуже добре відзначити, оскільки це важливо!
Прифтан

1
@Pryftan +1 для +1 за +1 ... ви знаєте ... це дійсно важливо.
0xc0de

@ 0xc0de Безумовно, згоден! Дякую за це! :)
Прифтан

15

Якщо коротко, IFS=$'\n'призначте нову рядок \nзмінній IFS.

$'string'Конструкція - це механізм цитування, який використовується для декодування ANSI C, як послідовності втечі Цей синтаксис походить від ksh93, і був портативним сучасної оболонці , як bash, zsh, pdksh, busybox sh.

Цей синтаксис не визначений POSIX, але був прийнятий для випуску 7 SUS .


-1

Я вважаю за краще пояснити $IFSчерез приклад:
Suppsoe, який ви хочете cp, mv або інший файл, що обробляє файл, IFS порожній за допомогою defualt, коли у ваших файлів є мета-діаграма або пробіл, наприклад:
Linux Administration.pdfабо Free Software Fundation.ogg, звичайно, у вас буде проблема, тому що: Linux вважає, що окремий парам і Administartion розглядають окремий парам. Отже, баш має built-in variable, тоді ви можете ініціалізуватись IFS==$(echo -en "\n\b"), Потім баш відкинути будь-які метапотоки та пробіл між назвою файлу, наприклад:

#!/bin/bash
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
mymusicdir=~/test/dd
find $mymusicdir -name "*" -execdir rename 's/ /_/g' "{}" +
IFS=$SAVEIFS
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.