Яке точне значення IFS = $ '\ n'?


124

Якщо наведено наступний приклад, який встановлює IFSзмінну середовища для символу каналу рядка ...

IFS=$'\n'
  • Що точно означає знак долара ?
  • Що це робить у цьому конкретному випадку?
  • Де я можу прочитати докладніше про це специфічне використання (Google не дозволяє спеціальних символів шукати, і я не знаю, що шукати інакше)?

Я знаю, що таке IFSзмінна середовище, і що таке \nсимвол (рядок каналу), але чому б просто не використовувати таку форму: IFS="\n"(яка не працює)?

Наприклад, якщо я хочу провести цикл через кожен рядок файлу і хочу використовувати цикл, я можу це зробити:

for line in (< /path/to/file); do
    echo "Line: $line"
done

Однак це не спрацює правильно, якщо IFSне встановлено символ подачі рядка. Щоб змусити його працювати, я повинен би зробити це:

OLDIFS=$IFS
IFS=$'\n'
for line in (< /path/to/file); do
    echo "Line: $line"
done
IFS=$OLDIFS

Примітка: мені не потрібен інший спосіб робити те саме, я знаю вже багато інших ... Мені цікаво лише це $'\n'і цікавилось, чи хтось міг би дати мені пояснення з цього приводу.

Відповіді:


161

Зазвичай bashне інтерпретує послідовності втечі в рядкових літералах. Так що, якщо ви пишете \nабо "\n"або '\n', що це не LINEBREAK - це лист n(в першому випадку) або зворотний слеш слід буква n(в двох інших випадках).

$'somestring'є синтаксисом рядкових літералів із послідовностями втечі . Так що в відміну '\n', на $'\n'самому ділі є LINEBREAK.


2
Не зовсім так - \nце просто (втекла) літера n. Ви маєте рацію , що '\n'і "\n"є люфт з подальшим п.
Роман Чепляка

15
Зауважте, що $'\n'специфічний для bash - він не працюватиме в оболонці POSIX ( /bin/sh). Щоб отримати той самий ефект, сумісний з POSIX, ви можете ввести IFS=', потім натисніть клавішу return, щоб ввести фактичний символ нового рядка, а потім набрати закриття'
Річард Хансен,

23
IFS=$(echo -e '\n')також слід це робити сумісно з POSIX.
Vineet

12
@Vineet - це дало мені паузу, щоб оскаржувати обґрунтований коментар. У той час як це є Posix-правильно, він не працює - оператори підстановки команд в БАШЕЄВ очистити дисплей повністю завершального символу нового рядка. Дивіться це для більш детальної інформації .
Цифрова травма

9
@DigitalTrauma Я думаю, це навіть не POSIX: -eне визначено і \nне -eпрацює як розширення XSI: pubs.opengroup.org/onlinepubs/9699919799/utilities/… . printf '\n'скелі;)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

20

Просто щоб дати конструкту його офіційна назва : такі рядки $'...'називаються ANSI C-рядки в лапках .

Тобто, як і у рядках [ANSI] C, послідовності відхилення люфтів розпізнаються та розширюються до їх буквального еквівалента (див. Нижче повний список підтримуваних послідовностей евакуації).

Після цього розширення $'...'рядки поводяться так само, як і '...'рядки, тобто вони трактуються як літерали, які НЕ піддаються жодним [подальшим] розширенням оболонок .

Наприклад, $'\n'розширюється до прямого символу нового рядка - що є чимось звичайним літералом bash string (незалежно від того, '...'чи "..."не може це зробити). [1]

Ще однією цікавою особливістю є те, що рядки з цитованими ANSI C можуть вийти '(одиничні лапки), оскільки\' , '...'(звичайні однорядкові рядки) не можуть:

echo $'Honey, I\'m home' # OK; this cannot be done with '...'

Список підтримуваних послідовностей втечі :

Послідовності втечі зворотного схилу, якщо вони є, декодуються наступним чином:

\ оповіщення (дзвінок)

\ b зворотній простір

\ e \ E символ втечі (не ANSI C)

\ f форму подачі

\ n новий рядок

повернення вагона

\ t горизонтальна вкладка

\ v вертикальна вкладка

\ зворотній кут

\ 'єдина цитата

\ "подвійна цитата

\ nnn восьми бітний символ, значення якого - вісімкове значення nnn (одна-три цифри)

\ xHH восьмирозрядний символ, значення якого - шістнадцяткове значення HH (одна або дві шістнадцяткові цифри)

\ uHHHH символ Unicode (ISO / IEC 10646), значення якого - шістнадцяткове значення HHHH (одна-чотири шістнадцяткові цифри)

\ UHHHHHHHH символ Unicode (ISO / IEC 10646), значення якого - шістнадцяткове значення HHHHHHHH (одна-вісім шістнадцяткових цифр)

\ cx символ керування x

Розширений результат одноцитований, як ніби знак долара не був.


[1] Однак ви можете вставляти фактичні нові рядки в рядки "..." та "..."; тобто ви можете визначити рядки, що охоплюють кілька рядків.


16

Від http://www.linuxtopia.org/online_books/bash_guide_for_beginners/sect_03_03.html :

Слова у формі "$" STRING "" трактуються особливим чином. Слово розширюється на рядок із заміненими символами зворотної косої риси, як це визначено стандартом ANSI-C. Послідовності втечі зворотного схилу можна знайти в документації Bash.found

Я думаю, що це змушує сценарій вийти з каналу рядка до відповідного стандарту ANSI-C.


8

Відновіть відновлення стандартних IFS - це OLDIFS=$IFSне потрібно. Запустіть новий IFS в допоміжній оболонці, щоб уникнути перевизначення стандартних IFS:

ar=(123 321); ( IFS=$'\n'; echo ${ar[*]} )

Крім того, я не дуже вірю, що ви відновите старий IFS повністю. Ви повинні двічі процитувати його , щоб уникнути розриву ліній , таких як OLDIFS="$IFS".


2
це дійсно корисна техніка. я просто використав його для більш чистої оболонки приєднатися цит: args=$(IFS='&'; echo "$*"). відновлення IFSдо $' \t\n'в Bourne оболонки дружньо не подвиг.
jeberle

Re Besides I don't really believe you recover the old IFS fully: Слово розщеплення НЕ виконується на рітах змінних завдань (але видалення котирування), так OLDIFS=$IFSі OLDIFS="$IFS"поводиться точно так само.
mklement0

3

ANSI C-котирування рядків є ключовим моментом. Завдяки @ mklement0.

Ви можете протестувати рядки, цитовані ANSI C, за допомогою команди od.

echo -n $'\n' | od -c
echo -n '\n' | od -c
echo -n $"\n" | od -c
echo -n "\n" | od -c

Виходи:

0000000  \n  
0000001

0000000   \   n   
0000002

0000000   \   n   
0000002

0000000   \   n   
0000002

Ви можете зрозуміти значення чітко за результатами.


-7

Це як отримати значення зі змінної:

VAR='test'
echo VAR
echo $VAR

різні, тому знак долара в основному оцінює зміст.


6
Це не має нічого спільного зі змінними. $'FOO'(на відміну від того, про $FOOяке це питання не йшлося) є рядковим літералом. Якщо ви виконаєте echo $'VAR', ви побачите, що він друкує рядок VAR, а не test.
sepp2k
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.