Я боролся с работой 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 (список пакетов с его архитектура)
Возможно, вы слишком много над этим задумались.
Немного.
Я заставил его работать с 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 = "[(] |),"
.
Вот альтернативный подход, который я придумал. Он точно соответствует вашему выводу. Вероятно, он менее эффективен из-за дополнительной операции split ()
для каждого элемента, но его легче читать и понимать.
#!/usr/bin/awk -f
BEGIN {
FS="), "
}
{
sub(/^Install:/, "")
for (i=1; i<=NF; i++) {
split($i, a, " ")
print a[1]
}
}
Есть гораздо более простой способ выполнить ту же задачу без использования awk. Вы можете использовать регулярные выражения Perl во многих версиях grep, которые входят в основные дистрибутивы Linux. В моей версии grep (GNU grep версии 2.27) следующий результат дает тот же результат, что и решение awk.
grep -oP '(?<=\),).*?(?=\()' input.txt > output.txt