bash змінює свою поведінку залежно від значення змінної "IFS"


18

Коли я встановлюю IFSзмінну на пробіл, bashрозглядає кілька пробілів як один простір ( myprogramце програма, яка друкує отримані аргументи командного рядка):

IFS=" "
x="hello   hi   world"
./myprogram $x
argv[1] = hello
argv[2] = hi
argv[3] = world

Але коли я встановлюю IFSзмінну комою, bashне трактує кілька коми як одну кому:

IFS=","
x="hello,,,hi,,,world"
./myprogram $x
argv[1] = hello
argv[2] = 
argv[3] = 
argv[4] = hi
argv[5] = 
argv[6] = 
argv[7] = world

Чому так?


Тільки для довідки, "IFS" означає " Внутрішній роздільник поля" .
pr1268

Відповіді:


21

Це задокументовано в Росії man bash. Одиничне виникнення будь-якого символу в IFS, який не є пробілом, обмежує поле.

Від man bash:

Оболонка розглядає кожен символ IFS як роздільник і розбиває результати інших розширень на слова, використовуючи ці символи як термінатори поля. Якщо IFS не встановлено, чи його значення в точності <space><tab><newline>, за замовчуванням, то послідовність <space>, <tab>і <newline>на початку і в кінці результатів попередніх розширень, ігнорується, а будь-яка послідовність символів МФСА не на початку або в кінці служить для визначення кордонів слова. Якщо IFS має значення, відмінне від типового, тоді послідовності пробілів символів пробілу, вкладки та новий рядок ігноруються на початку та в кінці слова, поки символ пробілу знаходиться у значенні IFS (символ пробілу IFS) ). Будь-який символ у IFS, який не є пробілом IFS, поряд із будь-якими суміжними символами пробілу IFS, обмежує поле. Послідовність символів пробілу IFS також розглядається як роздільник. Якщо значення IFS є нульовим, розщеплення слів не відбувається. [Наголос додано.]

Приклади: розділення поля

Якщо в IFS немає символів пробілу, то пробіли включаються в поля:

$ ( IFS=',' x='one , two,three'; printf "<%s>\n" $x )
<one >
< two>
<three>

Якщо в IFS є і пробіли, і кома, то послідовності пробілів з комою, а потім послідовності заготовок трактуються як один роздільник:

$ ( IFS=' ,' x='one , two,three'; printf "<%s>\n" $x )
<one>
<two>
<three>

Послідовності коми трактуються як послідовності порожніх полів:

$ ( IFS=' ,' x='one,,,two,three'; printf "<%s>\n" $x )
<one>
<>
<>
<two>
<three>

Приклади: провідна та кінцева пробіли

Якщо IFS не містить пробілів, то будь-яка провідна та кінцева пробіли зберігається у полях:

$ ( IFS=',' x='  one , two,three  ,'; printf "<%s>\n" $x )
<  one >
< two>
<three  >

Якщо IFS містить пробіли, то будь-які провідні або кінцеві послідовності пробілів видаляються:

$ ( IFS=' ,' x='  one , two,three  ,'; printf "<%s>\n" $x )
<one>
<two>
<three>

можливо також варто підкреслити "тоді послідовності пробілів символів пробілу, вкладку та новий рядок ігноруються на початку та в кінці слова, доки символ пробілу має значення IFS"
Джефф Шаллер

@JeffSchaller Відмінна ідея: я просто додав розділ про це.
John1024


що робити, якщо у вас є розділений на вкладку файл з деякими відсутніми значеннями? тобто ви не хочете, щоб послідовності вкладок розглядалися як одна вкладка. Крім того, поля містять коми, тому їх не можна використовувати як роздільник. Є єдиним рішенням використовувати якийсь інший роздільник (а не вкладки)?
Давос

@Davos Для даних із кожним полем, розділеним однією вкладкою, може бути більш природним використання інших інструментів, які легко впораються з цим, наприклад, awkз -F'\t'опцією або cut. З іншого боку , якщо у вас є остання версія bash, ви можете бути в змозі розібрати поля , використовуючи readarrayз -d$'\t'опцією.
John1024
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.