Разделитель полей по умолчанию для awk

Извините за этот глупый вопрос, но не уверен, что правильный ответ найден, поэтому разделитель по умолчанию - это просто пространство для awk?

Ответ 1

Вот прагматическое резюме, которое относится ко всем основным реализациям Awk:

  • GNU Awk (gawk) - awk по умолчанию в некоторых дистрибутивах Linux
  • Mawk (mawk) - awk по умолчанию в некоторых дистрибутивах Linux (например, в более ранних версиях Ubuntu Crysman сообщалось, что версия 19.04 теперь поставляется с GNU Awk - см. Его комментарий ниже.)
  • BSD Awk - также известный как BWK Awk - стандартный awk для BSD-подобных платформ, включая OSX

В Linux awk -W version сообщит вам, какой реализацией является awk по умолчанию.
BSD Awk понимает только awk --version (что GNU Awk понимает в дополнение к версии awk -W version).

Последние версии всех этих реализаций соответствуют стандарту POSIX в отношении разделителей полей [1] (но не разделителей записей).

Глоссарий:

  • RS является разделителем ввода-записи, который описывает, как вход разбивается на записи:

    • Значение по умолчанию для POSIX - это новая строка, также называемая \n ниже; по умолчанию вход разбит на строки.
    • В командной строке awk RS можно указать как -v RS=<sep>.
    • POSIX ограничивает RS буквальным односимвольным значением, но GNU Awk и Mawk поддерживают многосимвольные значения, которые могут быть расширенными регулярными выражениями (BSD Awk не поддерживает это).
  • FS - входной разделитель -F ield, который описывает, как каждая запись разбивается на поля; это может быть расширенное регулярное выражение.

    • В командной строке awk FS можно указать как -F <sep> (или -v FS=<sep>).
    • Обязательное значение по умолчанию для POSIX - это пробел (0x20), но этот пробел буквально не интерпретируется как (единственный) разделитель, но имеет особое значение; увидеть ниже.

По умолчанию:

  • любой пробел и/или табуляция и/или перевод строки рассматриваются как разделитель полей
  • с ведущими и ведомыми пробегами игнорируется.

POSIX спец.использует абстракцию <blank> для пробелов и табуляций, что верно для всех локалей, но может содержать дополнительные символы в определенных локалях - я не знаю, существуют ли такие локали.

Обратите внимание, что с разделителем ввода-записи по умолчанию (RS), \n, символы новой строки обычно не вводят изображение в качестве разделителей полей, потому что ни одна запись не содержит \n в этом случае.

Однако в игру вступают новые строки как разделители полей:

  • Когда для RS задано значение, которое приводит к тому, что сами записи содержат \n экземпляры (например, когда для RS задана пустая строка; см. Ниже).
  • Обычно, когда функция split() используется для разбиения строки на элементы массива без явного аргумента разделителя -F ield.
    • Несмотря на то, что входные записи не будут содержать \n экземпляров в случае использования RS по умолчанию, функция split() вызывается без явного аргумента-разделителя полей для многострочной строки из другого источника (например, переменной передается через -v или как псевдо -F имя_устройства) всегда обрабатывает \n как разделитель полей.

Важные НЕ по умолчанию соображения:

  • Присвоение пустой строки RS имеет особое значение: она считывает ввод в режиме абзаца, что означает, что ввод разбивается на записи по сериям непустых строк, а начальные и конечные серии пустых строк игнорируются.

  • Когда вы назначаете что-либо кроме буквального пространства для FS, интерпретация FS кардинально меняется:

    • Отдельный символ или каждый символ из указанного набора символов распознается отдельно как разделитель полей, а не как его по умолчанию.
      • Например, если задать для FS значение [ ] - даже если оно фактически составляет один пробел - каждый отдельный экземпляр пространства в каждой записи будет рассматриваться как разделитель полей.
      • Чтобы распознать прогоны, необходимо использовать квантификатор regex (символ дублирования) +; например, [\t]+ распознает серии вкладок как один разделитель.
    • Начальные и конечные разделители НЕ игнорируются, а вместо этого разделяют пустые поля.
    • Установка FS в пустую строку означает, что каждый символ записи является своим собственным полем.
  • В соответствии с предписаниями POSIX, если для RS задана пустая строка (режим абзаца), символы новой строки (\n) также считаются разделителями полей независимо от значения FS.

[1] К сожалению, GNU Awk вплоть до версии не ниже 4.1.3 соответствует устаревшему стандарту POSIX в отношении разделителей полей, когда вы используете опцию для обеспечения соответствия POSIX, -P (--Posix): с этой опцией в действительности, и для RS задано непустое значение, символы новой строки (\n экземпляры) НЕ распознаются как разделители полей.В руководстве по GNU Awk изложено устаревшее поведение (но не следует упоминать, что оно не применяется, если для RS задана пустая строка).Стандарт POSIX изменился в 2008 году (см. Комментарии), чтобы также учитывать разделители полей новой строки, когда FS имеет значение по умолчанию - как GNU Awk всегда делал без -P (--Posix).
Вот 2 команды, которые проверяют поведение, описанное выше:
* При -P и RS -P пустой строке, \n по-прежнему рассматривается как разделитель полей:
gawk -P -F' ' -v RS='' '{ printf "<%s>, <%s>\n", $1, $2 }' <<< $'a\nb'
* При -P и -P RS \n НЕ рассматривается как разделитель полей - это устаревшее поведение:
gawk -P -F' ' -v RS='|' '{ printf "<%s>, <%s>\n", $1, $2 }' <<< $'a\nb'
По словам тех, кто сопровождает GNU Awk, грядет исправление;ожидайте этого в версии 4.2 (временные рамки не указаны).
(Наконечник шляпы @JohnKugelman и @EdMorton за их помощь.)

Ответ 2

Вопрос the default delimiter is only space for awk? неоднозначен, но я постараюсь ответить на оба вопроса, которые вы можете задать.

Значение по умолчанию для переменной FS (которая содержит разделитель полей, которая сообщает awk, как разделять записи в полях при их чтении) является одиночным символом пробела.

То, что awk использует для разделения записей в полях, является "разделителем полей", который является регулярным выражением с некоторыми дополнительными функциями, которые применяются только тогда, когда разделитель полей является единственным пустым символом. Эта дополнительная функциональность такова:

  • Ведущее и конечное пробелы игнорируются при разделении поля.
  • Поля разделяются цепочками смежных пробелов, которые включают пробелы, вкладки и символы новой строки.
  • Если вы хотите использовать буквенный пустой символ в качестве разделителя полей, вы должны указать его как [ ], а не только отдельный литерал пустой char, как вы могли бы в regexp.

В дополнение к разделителям полей, используемым для разделения записей на поля при чтении ввода, они используются в некоторых других контекстах, например. третий arg для split(), поэтому вам важно знать, какие контексты требуют строку или регулярное выражение или полеsesep, а man-страница четко определяет каждый.

Помимо всего прочего, это объясняет следующее:

$ echo ' a b c ' | awk '{printf "%d: <%s> <%s> <%s>\n", NF, $1, $2, $3}'
3: <a> <b> <c>
$ echo ' a b c ' | awk -F' ' '{printf "%d: <%s> <%s> <%s>\n", NF, $1, $2, $3}'
3: <a> <b> <c>
$ echo ' a b c ' | awk -F'[ ]' '{printf "%d: <%s> <%s> <%s>\n", NF, $1, $2, $3}'                              
5: <> <a> <b>

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

Ответ 3

Посмотрим на страницу GNU awk man:

FS — Разделитель полей ввода, пробел по умолчанию. См. Поля выше.

В раздел "Поля"!

По мере чтения каждой входной записи gawk разбивает запись на поля, используя значение переменной FS в качестве разделителя полей. Если FS - один символ, поля разделяются этим символом. Если FS - пустая строка, то каждый отдельный символ становится отдельным полем. В противном случае ожидается, что FS будет полным регулярным выражением. В специальном случае, когда FS является единственным пространством, поля разделяются пробелами пробелов и/или вкладок и/или строк новой строки.