Этот ответ предоставляет два решения - решение Gnu Awk и версию POSIX.
POSIX awk
awk '{r=r ? r "\n" $0 : $0}
/\|##\|$/ { if (r ~ /"/) print r; r=""}' inputfile > outputfile
GNU awk 1
awk 'BEGIN{RS="\\|##\\|\n?";ORS="|##|\n"}/"/' inputfile > outputfile
GNU awk 2
awk 'BEGIN{RS="\\|##\\|\n?"}/"/{printf $0 RT}' inputfile > outputfile
На приведенных в вопросе данных примера все предоставленные решения дают следующий вывод:
10358|*|BI-MED-CDMA-MCS-90-118-EXAM|*|Exam for 001-MCS-90-118:
Planning, Conducting and Reporting Post Marketing Surveillance "Studies and Safety Reporting from Non Trial Activities |*|GLOBAL_MEDICAL|*||*|Y|*|N|*||*|CFC6E822849A0A7AE040800AA5644B19|*|finke|*|2012.04.30 04:23:27|##|
примечание: Возможно, у вас возникла проблема возврата каретки, если файл поступил с компьютера Windows.Пожалуйста, запустите файл dos2unix
, прежде чем использовать его с этими инструментами.
Как это работает?(POSIX)
Используя POSIX-версию awk , мы можем сделать
awk '{r=r ? r "\n" $0 : $0}
/\|##\|$/ { if (r ~ /"/) print r; r=""}' inputfile > outputfile
Идея состоит в том, чтобы создать запись r
с помощьюдобавление каждой строки к r
.Если текущая строка заканчивается на "|##|"
, то мы проверяем, содержит ли запись r
"
.Если это так, мы печатаем запись r
и сбрасываем запись r
в пустую строку.Если он не содержит, мы просто сбросили его.
Как это работает?(GNU)
Используя GNU awk , вы можете сделать это напрямую, используя разделитель записей RS
awk 'BEGIN{RS="\\|##\\|\n?";ORS="|##|\n"}/"/' inputfile > outputfile
Идея в том, чтофайл содержит различные записи.В ОП четко указывалось, что информация записи разделена на поля, разделенные |*|
, но, что более важно, сами записи разделены |##|
.Таким образом, в представленном примере OP первая запись - это строка 1, а вторая запись - в строке 2 и в строке 3.
В awk вы можете определить разделитель записей с помощьюпеременной RS
.В состоянии по умолчанию RS
- это символ \n
, который делает каждую строку отдельной записью, на которую может ссылаться $0
.В POSIX разделителем записей может быть только один символ, который разделяет записи, в то время как в Gnu awk это может быть регулярное выражение (см. Добавление ниже).
Поскольку разделителем записей OP является строка"| ## |"после всех или без символа \n
нам нужно определить RS=\\|##\\|\n?
.Почему это так сложно?
символ |
- это операция ИЛИ (оператор чередования) в регулярном выражении, поэтому мы должны ее избежать.Но поскольку строковые литералы, которые используются в качестве регулярных выражений, анализируются дважды, нам также необходимо избегать его дважды.Так что |
→ \\|
(см. здесь )
\n?
потому, что кажется, что фактическим разделителем записей является строка "| ##| \ n ", но, возможно, некоторые записи не имеют символа новой строки, особенно последняя запись.
Когда вы печатаете записи, используя оператор print
, он автоматически добавляет выходную записьразделитель ORS
после каждой строки.По умолчанию это снова символ \n
.Поскольку разделитель записей RS
не является частью записи $0
, необходимо обновить значение ORS
до ORS="|##|\n"
.На этот раз не является регулярным выражением, поэтому вам вообще не нужно экранировать.
Оператор /"/
является сокращением для /"/{print $0}
, что означает Если текущая запись $0
содержит"
, затем выведите текущую запись $0
, за которой следует разделитель выходных записей ORS
.
Примечание: , поскольку мы фактически уже используем Gnu awk, мы можем фактическиуменьшите все это еще больше до:
awk 'BEGIN{RS="\\|##\\|\n?"}/"/{printf $0 RT}' inputfile > outputfile
, который использует разделитель соответствующих записей RT
, который соответствует тексту, найденному RS
.Заменив оператор print
на оператор printf
, нам больше не нужно ORS
и просто вручную добавьте RT
к записи $0
.
RS
: Разделитель входных записей.Его значением по умолчанию является строка, содержащая один символ новой строки, что означает, что входная запись состоит из одной строки текста.Это также может быть пустая строка, в этом случае записи разделяются сериями пустых строк.Если это регулярное выражение, записи разделяются совпадениями регулярного выражения во входном тексте.
Способность RS
быть регулярным выражением является расширением gawk
.В большинстве других реализаций AWK, или если gawk
находится в режиме совместимости (см. Опции), используется только первый символ значения RS
.
ORS
: Разделитель выходной записи.Он выводится в конце каждого оператора печати.Значением по умолчанию является "\ n", символ новой строки.
RT
: (специфично для GNU AWK) Входной текст, который соответствует тексту, обозначенному RS
, разделителем записей.Он устанавливается каждый раз при чтении записи.
источник: Руководство по GNU AWK