GAWK использует круглые скобки как FS

Я боролся с работой gawk при установке регулярного выражения в FS как space-open_parenthersis ИЛИ close_parenthesis-coma-space. Я пробовал несколько подходов, ни один из которых не дает желаемого поведения 1-й. FS = "(() | (),)" 2-й. FS = "[(() (),)]" 3-й (по ASCII-коду OCT) FS = "[(\ 040 \ 050) (\ 051 \ 054 \ 040)]" 4-й FS = "((\ 040 \ 050) | (\ 051 \ 054 \ 040))"

мой входной файл - это https://phpaste.sourceforge.io/demo /paste.php?id=144 это файл только с одной записью (строкой) моего журнала apt-get в Debian, в котором перечислены некоторые пакеты.

моя программа gawk такова

#! /usr/bin/gawk -f
BEGIN {FS = "[(\040\050)(\051\054\040]"}
{
for(i=1;i<=NF;i=i+2) #I increased i by 2 because i want to print the odd numbered fields(only the names of the packages:architecture)  
    print $i
}`

Я выполню ее в bash как myawk.awk input.txt> output.txt


Я с удовольствием добавлю здесь большое слово FXXX !!!! Потому что я только что решил это. Думаю, в награду за попытки. Я использовал FS = "(\\ s \\\ 050) | (\\\ 051, \\ s)" , и это помогло, даже несмотря на то, что я действительно не понимаю, почему три обратной косой черты \\\ перед окт-кодом ASCII.

Не мог бы кто-нибудь дать какое-нибудь объяснение по этому поводу. Вроде почему ?? Я читал, что AWK дважды читал регулярное выражение, и для этого потребуется \\ , но мне нужно было \\\ (три !!!).

Также приветствуются любые альтернативные или различные подходы!

Заранее спасибо!

это мой желаемый результат, и, к счастью, я получил его во время последнего прогона https://phpaste.sourceforge.io/demo/paste.php?id=145 (список пакетов с его архитектура)

0
21.02.2017, 06:53
3 ответа

Возможно, вы слишком много над этим задумались. Немного. Я заставил его работать с FS = "\\ (| \\)," , и даже смог сократить его до FS = "\\ (|), ".

  • Похоже, вы полагали, что вам нужно выполнить " ( регулярное выражение 1 ) | ( регулярное выражение 2 ) ", когда все, что вам нужно было сделать, это " регулярное выражение 1 | регулярное выражение 2 ".
  • Вы, кажется, полагали, что, заключив круглые скобки в группирующие круглые скобки, внутренние круглые скобки превратятся в буквальные, текстовые скобки. Это не так. Группировка регулярных выражений может быть вложенной; чтобы рассматривать круглые скобки как буквальные текстовые скобки, вам нужно их экранировать.
  • ) является особенным в регулярном выражении только внутри группы. Если ( экранирован, ) не требуется.

Вот тут-то и бывает сложно. Наивно, исходя из вышеизложенного, FS = "\ (|)," должно быть достаточно хорошо. Но у GAWK есть проблема с регулярными выражениями в строковых константах; она обсуждается в Руководстве пользователя GNU Awk, раздел 9.1.3.1 . Он ориентирован на получение буквального значения & в тексте замены для sub () , gsub () или Вызов gensub () , , но он, кажется, применим и к FS :

… есть несколько уровней обработки выхода , идущих на.

Во-первых, есть лексический уровень , , когда awk читает вашу программу и создает ее внутреннюю копию для выполнения. Затем есть уровень времени выполнения, , когда awk фактически сканирует [программу и определяет, как ее выполнять].

На обоих уровнях awk ищет определенный набор символов , который может идти после обратной косой черты. На лексическом уровне он ищет escape-последовательности, перечисленные в Escape Sequences . Таким образом, для каждого ‘\’, который awk обрабатывает на уровне выполнения, вы должны ввести две обратные косые черты на лексическом уровне.

Курсор (последнее предложение) добавлен. Кажется, это означает, что если мы хотим установить FS на "\ (|)," (чтобы избежать левой скобки , , чтобы рассматривать круглые скобки как буквальные, текстовые скобки), вам необходимо присвоить FS = "\\ (|)," или указать -F '\\ (|),' (чтобы избежать обратной косой черты). Вы можете проверить это с помощью простого теста: Запустите awk -F '\\ (|),' , а затем распечатайте FS изнутри ваша программа. Он будет отображаться как ⁠ \ (|), ⁠ .


В общем, если вы хотите превратить специальный символ в обычный (или, иногда, наоборот), общий традиционный подход состоит в том, чтобы экранировать его с помощью a \ (обратная косая черта). Но есть еще один механизм, специфичный для регулярных выражений: используйте выражение […] . В выражениях […] используются только специальные символы: ^ , - и ] (и это зависит от позиции).

  • [pq] означает p или q ]
  • [()] означает ( или )
  • [(p] означает ( или p
  • ] [(] означает a ( или… ну, поскольку других символов нет, это просто означает буквальный (.

Итак, если у вас аллергия на обратная косая черта, вы можете установить FS = "[(] |)," .

1
28.01.2020, 02:46

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

#!/usr/bin/awk -f

BEGIN { 
    FS="), "
}
{
    sub(/^Install:/, "") 
    for (i=1; i<=NF; i++) { 
        split($i, a, " ")
        print a[1]
    }
}
0
28.01.2020, 02:46

Есть гораздо более простой способ выполнить ту же задачу без использования awk. Вы можете использовать регулярные выражения Perl во многих версиях grep, которые входят в основные дистрибутивы Linux. В моей версии grep (GNU grep версии 2.27) следующий результат дает тот же результат, что и решение awk.

grep -oP '(?<=\),).*?(?=\()' input.txt > output.txt
0
28.01.2020, 02:46

Теги

Похожие вопросы