как я могу сохранить встроенный символ табуляции - PullRequest
1 голос
/ 10 октября 2019
  • РЕДАКТИРОВАТЬ 2019-Oct-11 - Простой пример
    • удален предыдущий пример

Я хочу, чтобы awk повторно считал TABсимвол, встроенный в $0 в качестве содержимого, когда он обрабатывает входную запись $0 после изменения значения поля ($1, $2, ..).

Вот краткий пример. Например, в выводе ниже «t @ 48» означает, что в позиции 48 записи данных $0 имеется TAB. Обратите внимание, что «\t» расширен до: TAB chr (9) в качестве начальной обработки ввода (помечено raw ).

Пример вывода :

 $ ./tmp.awk   tmp.input 

raw $0:      '    line with spaces here     a tab between AAA\tBBB', t @ 0, NF = 8, len = 52.
$1:          'line', len = 4.
unescape $0: '    line with spaces here     a tab between AAA   BBB', t @ 48, NF = 9, len = 51.

$1 = $1, $0: 'line with spaces here a tab between AAA BBB', t @ 0, NF = 9, len = 43.

unescape $0: '    line with spaces here     a tab between AAA   BBB', t @ 48, NF = 9, len = 51.
$1 = "", $0: ' with spaces here a tab between AAA BBB', t @ 0, NF = 9, len = 39.

final $0:    ' with spaces here a tab between AAA BBB', t @ 0, NF = 9, len = 39.

Когда "\t" расширен и $ 0 обновлен, awk правильно перестраивает и дает 9 полей (больше 8). ( тик )

Входная запись :

line with spaces here     a tab between AAA\tBBB

Желаемый Результат :

Конечная цель состоит в том, чтобы иметь возможность удалить содержимое поля $ 1, сохранив при этом все форматирование и интервал будет , как показано.

 $0:  '     with spaces here     a tab between AAA  BBB', t @ 44, NF = 8, len = 47.

С удалением только указанных $1 -символов, что является "линией". Включая TAB между "AAA" и "BBB". Я показал на одно поле меньше (NF = 8). Сам Awk, похоже, сохраняет пустую ячейку $1, поэтому NF = 9 также будет приемлемым.

После строки, помеченной: $1 = $1', когда мы изменяем значение $1 2 .

{
     :
print "    unescape $0: '" $0 "', t @ " index( $0, "\t" ) ", NF = " NF ", len = " length( $0 ) ".";

    $1 = $1;  # force record to be reconstituted

print "    $1 = $1, $0: '" $0 "', t @ " index( $0, "\t" ) ", NF = " NF ", len = " length( $0 ) ".";

}   

output ...

unescape $0: '    line with spaces here     a tab between AAA   BBB', t @ 48, NF = 9, len = 51.
$1 = $1, $0: 'line with spaces here a tab between AAA BBB', t @ 0, NF = 9, len = 43.

Обратите внимание, что пока у меня еще есть 7 полей в этой строке. НЕТ ДЛИННОГО TAB символа, и после пробела «здесь» были удалены пробелы. Эти изменения форматирования нежелательны для этого варианта использования.

Я получаю этот результат согласованно НЕТ, какие бы значения я ни вводил для разделителя полей, FS (даже перевод строки) и OFS. На самом деле изменение OFS ухудшает ситуацию.

Поведение не ожидалось. Однако после некоторых комментариев вполне возможно, что это предписано, несмотря ни на что.

Образец awk скрипт:

{
    print "";
    print "raw $0:      '" $0 "', t @ " index( $0, "\t" ) ", NF = " NF ", len = " length( $0 ) ".";
    print "$1:          '" $1 "', len = " length( $1 ) ".";

    gsub(/\\t/, "\t", $0);      #  expand any embedded TAB-s
    print "unescape $0: '" $0 "', t @ " index( $0, "\t" ) ", NF = " NF ", len = " length( $0 ) ".";
    preserve = $0;

    print "";
    $1 = $1;  # force record to be reconstituted
    print "$1 = $1, $0: '" $0 "', t @ " index( $0, "\t" ) ", NF = " NF ", len = " length( $0 ) ".";

    print "";
    $0 = preserve;
    print "unescape $0: '" $0 "', t @ " index( $0, "\t" ) ", NF = " NF ", len = " length( $0 ) ".";

    $1 = "";   

    print "$1 = \"\", $0: '" $0 "', t @ " index( $0, "\t" ) ", NF = " NF ", len = " length( $0 ) ".";
    print "";

    print "final $0:    '" $0 "', t @ " index( $0, "\t" ) ", NF = " NF ", len = " length( $0 ) ".";
    print "";

}

Вопросы ...

  1. Как я могу получить желаемое поведение? Смысл, нет редактирования записи при удалении поля?
    • Если это невозможно - существует ли метод, который сохраняет целостность и интервал «текущей» записи $ 0?
    • Например, я искал массив, который отображает все поляк записи $ 0, но не нашел ее.
  2. Как можно сохранить TAB в примере.
  3. Можно ли предотвратить редактирование записи $0?

Символы были удалены. Изучение показывает, что awk отредактировал повторные пробелы (удалил их) и TAB.

Единственный пробел не является виновником, он, по-видимому, является восстановлением или изготовлением записи за 0 долларов.

Ссылка :

Области из UG ... Руководство пользователя Gnu Awk :

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

Я понял, что пространство FS особенное. Однако даже когда я ставлю странную FS, такую ​​как "W" и "\ n", символы все равно удаляются из $0 после шага перестройки $1 = $1.

  • Вывод FS не используется при повторной обработке $0

Изменение значения $0 = new string сработало, как и ожидалось. Количество полей увеличивается, потому что awk распознает символ табуляции. Я должен указать, что awk в этом случае не удалял вкладку (как хотелось бы).

Изменение полей (Gnu Awk UG) :

Наконец, бывают случаи, когда удобно заставить awk восстановить всю запись, используя текущуюЗначения полей и ОФС. Для этого используйте, казалось бы, безобидное задание:

  $1 = $1   # force record to be reconstituted
  print $0  # or whatever else with $0

Это заставляет awk восстановить запись. Это помогает добавить комментарий, как мы показали здесь.

Используемая версия:

gawk -VGNU Awk 4.2.1, API: 2.0 (GNU MPFR 4.0.2, GNU MP 6.1.2)Copyright (C) 1989, 1991-2018 Free Software Foundation

Ubuntu 19.04

Эта инструкция не предупреждает, что в $0 может быть удалено 9 символов, или даже намекает, что это повлияет на $ 0.

Другоенеобъяснимые аспекты:

  • У меня есть объяснение этому?
  • Это только gawk или распространено среди альтернативных awk -s?

Лично меня очень порадовало $0 не меняется. Много раз, когда я хочу awk за его способность структурировать данные и сохранять неструктурированный источник для вывода.

Жду ваших мыслей.

1 Ответ

2 голосов
/ 10 октября 2019

Вот моя попытка ответить на ваш вопрос.

1-й ответ (почему вкладки НЕ сохраняются): В awk что означает $1=$1: Когда мы делаем $1=$1 для любой строки, это означает, что мы просим awk перестроить линию, теперь это на самом деле означает? Это означает взять OFS (разделитель выходного поля) на рисунке. Чье значение из коробки (по умолчанию) будет пробелом. Вот пример для этого:

Давайте иметь следующий Input_file:

cat Input_file
a       b       c       d e

1-й сценарий: Теперь, когда я запускаю первый кодбез упоминания какого-либо значения OFS, затем посмотрите, что произойдет:

awk '1' Input_file
a       b       c       d e

Он печатает строку, как указано в Input_file, без изменений.


2-й сценарий: Теперь давайте определим значение OFS для \t здесь и запустим программу:

awk 'BEGIN{OFS="\t"};1' 
a       b       c       d e

Вы могли все еще увидеть НЕТ изменений в Output, хотя мы установили OFS="\t".


3-й сценарий: Теперь давайте возьмем пример 3-го сценария, в котором мы устанавливаем значение OFS="\t" и перестраиваем линию:

awk 'BEGIN{OFS="\t"} {$1=$1} 1' Input_file
a       b       c       d       e

Вы могли видеть, что теперь произошла TAB между символами d и e, потому что, когда мы попросили awk перестроить строку, она приняла во внимание OFS и реализовала ее для всей строкиполя, поэтому, следовательно, TAB появился на свет.

со страницы man awk:

При назначении значения существующему полю вся запись будет перестроена, когда $ 0ссылки. Аналогичным образом, присвоение значения $ 0 приводит к повторному разделению записи и созданию новых значений для полей.



2-й ответ (Как сохранить вкладки ипробелы, как для строки): Теперь возьмем пример того же Input_file, упомянутого выше. Допустим, вы хотите заменить символ e в нем, не вставляя TAB между d и e, тогда мы могли бы просто заменить его, и он не должен вставлять TAB между d и e следующим образом:

cat Input_file
a       b       c       d e
awk 'BEGIN{OFS="\t"}{sub(/e/,"f")}1' Input_file
a       b       c       d f


3-й ответ (о присвоении значения всей строке): Давайте посмотрим на эти примеры.

awk 'BEGIN{OFS="\t"} {$0="1 2 3 4 5"} 1' Input_file
1 2 3 4 5

Мы могли видеть назначение новой переменной, в то время как строка не устанавливала TAB в качестве разделителя, поскольку перестроение строки никогда не происходило, теперь давайте посмотрим, что происходит при перестроении строки.

wk 'BEGIN{OFS="\t"} {$0="1 2 3 4 5";$1=$1} 1' Input_file
1       2       3       4       5

Надеюсь, я правильно понял ваш вопрос, если есть еще вопросы, не стесняйтесь комментировать в этом посте. Также я проверил с этим примером файла, что длина файла Input_file не изменилась, вам нужно предоставить образцы в вашем посте (вопрос) для того же, чтобы понять это лучше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...