Каково точное значение IFS = $ '\ n'?

125

Если следующий пример, который устанавливает IFSпеременную среды в символ перевода строки ...

IFS=$'\n'
  • Что именно означает знак доллара ?
  • Что он делает в этом конкретном случае?
  • Где я могу узнать больше об этом конкретном использовании (Google не допускает использование специальных символов в поиске, и я не знаю, что искать в противном случае)?

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

Например, если я хочу перебрать каждую строку файла и использовать цикл for, я могу сделать это:

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не интерпретирует escape-последовательности в строковых литералах. Итак, если вы пишете \nили "\n"или '\n', это не перенос строки - это буква n(в первом случае) или обратная косая черта, за которой следует буква n(в двух других случаях).

$'somestring'это синтаксис для строковых литералов с escape-последовательностями . Так что в отличие '\n', на $'\n'самом деле является LINEBREAK.

sepp2k
источник
2
Не совсем так - \nэто просто (экранированная) буква n. Вы правы, что '\n'и "\n"есть люфт с последующим n.
Роман Чепляка 08
15
Обратите внимание, что $'\n'это специфично для bash - он не будет работать в оболочке POSIX ( /bin/sh). Чтобы получить тот же эффект в соответствии с POSIX, вы можете ввести IFS=', затем нажать return, чтобы ввести фактический символ новой строки, а затем ввести закрытие'
Ричард Хансен
23
IFS=$(echo -e '\n')также должен делать это POSIX-совместимым способом.
Vineet
12
@Vineet - это заставило меня задуматься, чтобы оспорить одобренный комментарий. В то время как это является Posix-правильно, он не работает - операторы подстановки команд в Баше удалить все символы завершающего символа новой строки. См. Это для более подробной информации .
Digital Trauma
9
@DigitalTrauma Я думаю, что это даже не POSIX: -eне определен и \nбез него -eработает как расширение XSI: pubs.opengroup.org/onlinepubs/9699919799/utilities/… . printf '\n'скалы;)
Чиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
21

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

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

После этого раскрытия $'...'строки ведут себя так же, как '...'строки, т. Е. Они рассматриваются как литералы, НЕ подлежащие каким-либо [дальнейшим] расширениям оболочки .

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

Еще одна интересная особенность заключается в том, что строки в кавычках ANSI C могут экранировать '(одинарные кавычки) как\' , чего '...'(обычные одинарные кавычки) не могут:

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

Список поддерживаемых escape-последовательностей :

Управляющие последовательности с обратной косой чертой, если они есть, декодируются следующим образом:

\ оповещение (звонок)

\ b backspace

\ e \ E escape-символ (не ANSI C)

\ f подача формы

\ n новая строка

\ r возврат каретки

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

\ v вертикальная табуляция

\ обратная косая черта

одинарная кавычка

\ "двойная кавычка

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

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

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

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

\ cx символ control-x

Расширенный результат заключен в одинарные кавычки, как если бы знака доллара не было.


[1] Вы можете, однако, встроить настоящие символы новой строки в строки '...' и "..."; то есть вы можете определить строки, которые охватывают несколько строк.

mklement0
источник
16

Из http://www.linuxtopia.org/online_books/bash_guide_for_beginners/sect_03_03.html :

Слова в форме «$ 'STRING'» обрабатываются особым образом. Слово расширяется до строки с замененными символами, экранированными обратной косой чертой, в соответствии со стандартом ANSI-C. Управляющие последовательности с обратной косой чертой можно найти в документации Bash.

Я предполагаю, что это заставляет скрипт уйти от перевода строки в соответствии с надлежащим стандартом ANSI-C.

Брэд Свердфегер
источник
8

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

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

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

Marek
источник
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

разные, поэтому знак доллара в основном оценивает содержание.

Pieter
источник
6
Это не имеет ничего общего с переменными. $'FOO'(в отличие от того, о $FOOчем не шла речь) - строковый литерал. Если вы выполните echo $'VAR', вы увидите, что он печатает строку VAR, а не test.
sepp2k 08