Команда Awk в режиме абзаца, но с пропуском пустых строк

У меня есть один файл с несколькими элементами <elem>...</elem>. Мне нужно разбить этот файл на n файлов с m элементами в каждом (аргумент передается команде awk, которую я использую). Например, если в моем исходном файле 40 элементов, я бы хотел разделить его на 3 файла (10 элементов, 13 элементов и 17 элементов).

Проблема в том, что в исходном файле есть элементы с разной структурой.

EDITED AFTER fedorqui comment:
I use as awk command as files I want to get at the end of the process. 
That means If I need 3 files with m1, m2 and m3 elements, I will 
execute 3 awk with different parameters

Пример ввода (file.txt) (5 элементов)

<elem>aaaaaaaa1</elem>
<elem>aaaaaaaa2</elem>
<elem>bbbbbbbb
bbbbbbbbb
bbbbbbbbb</elem>
<elem>bbbbbbbb2</elem>
<elem>ccccc

cccc</elem>

Как видите, 1-й/2-й/4-й элемент находится в одной строке, 3-й элемент находится в 3-х строках без пустых строк и 5-й элемент находится в 3-х строках с пустой строкой.

Пустые строки между элементами не являются проблемой, но пустые строки внутри элемента не являются проблемой

Пример желаемого результата:

file_1.txt (2 элемента)

<elem>aaaaaaaa1</elem>
<elem>aaaaaaaa2</elem>

file_2.txt (2 элемента)

<elem>bbbbbbbb
bbbbbbbbb
bbbbbbbbb</elem>
<elem>bbbbbbbb2</elem>

file_3.txt (1 элемент)

<elem>ccccc

cccc</elem>

команда AWK

(suffixFile — это суффикс файла. Например, fileAux_1.txt, fileAux_2.txt...)

Попытка1

awk -v numElems=$1 -v suffixFile=$2 '{
    for(i=1;i<=numElems;i++) {
        printf "<doc>"$i > "fileAux_" suffixFile".txt"
    }
}' RS='' FS='<doc>' file.txt

Работает, кроме пустых строк внутри элемента. Я понимаю, почему это терпит неудачу, потому что RS='' говорит awk разбить пустые строки

Попытка 2

awk -v numElems=$1 -v suffixFile=$2 '{
    for(i=1;i<=numElems;i++) {
        printf $i > "fileAux_" suffixFile".txt"
    }
}' RS='<doc>' FS='<doc>' file.txt

Другой подход, но он также терпит неудачу

Может кто-нибудь помочь мне?

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


person javi    schedule 09.01.2015    source источник
comment
как вы определяете, что должно идти на file_1 и что делать file_2? Это основано на первой букве в содержании тега <elem>?   -  person fedorqui 'SO stop harming'    schedule 09.01.2015
comment
Неважно, какой ‹elem› к какому файлу относится (я передаю два аргумента команде awk для решения этого вопроса). Я имею в виду, что я использую (например) awk -va=3 -vb=1 .... file.txt для отправки 3 элементов в file_1.txt и awk -va=2 -vb=2 ... file.txt для отправка 2 элементов в file_2.txt.   -  person javi    schedule 09.01.2015
comment
Я отредактировал пост с этим уточнением (спасибо)   -  person javi    schedule 09.01.2015
comment
Вы очень хорошо детализируете вопрос, но все же мне немного не понятна вся проблема. Не могли бы вы предоставить пример ввода, который работает, вместе с выводом? Затем покажите образец ввода, который не соответствует (полагаю, это тот, который вы показываете сейчас) и точно укажите, какая часть вывода неверна?   -  person fedorqui 'SO stop harming'    schedule 09.01.2015
comment
Хорошо, федорки. Я отвечу вам в ответ, потому что текстовое поле редактирования хуже, чем текстовое поле ответа   -  person javi    schedule 09.01.2015
comment
Нет, нет, пожалуйста, отредактируйте свой вопрос, ответы предназначены для ответа :) Вы можете увеличить раздел редактирования, перетащив его вниз. Просто опубликуйте команду, которая работает (awk -v numElems=1 и т. д.), и ту, которая не работает.   -  person fedorqui 'SO stop harming'    schedule 09.01.2015
comment
Ой, я сделал это прямо сейчас. Простите за неудобства :(   -  person javi    schedule 09.01.2015
comment
Прочтите Как задать хороший вопрос?, особенно раздел Включите ровно столько кода, чтобы другие воспроизвести проблему. Чтобы получить помощь в этом, прочитайте Как создать минимальный, полный и проверяемый пример.   -  person fedorqui 'SO stop harming'    schedule 09.01.2015
comment
Привет федорки. Думаю, теперь прояснилось (я изменил заголовок и дал вам пример в ответе)   -  person javi    schedule 09.01.2015
comment
Я просмотрел ваш код, провел некоторое исследование и не смог найти правильного решения. Поскольку это файл xml, я бы предложил, например, использовать какой-нибудь парсер XML в Python.   -  person fedorqui 'SO stop harming'    schedule 10.01.2015


Ответы (1)


Предполагая, что я правильно понял вашу задачу, вот моя попытка:

$ cat script.sh 
#!/bin/bash

awk -v numElems=$1 -v suffixFile=$2 '
        /<elem>/{var++}
        /<\/elem>/{var--; count++} 
        {if(count < numElems || (count == numElems && var == 0)) {
                print $0 >> "file_"suffixFile".txt"
        } else {
                print $0
        } }' $3

Сценарий в основном отслеживает замыкания <elem> и </elem> с var и подсчитывает пары с count. Затем оператор if решает, помещать ли строку в файл или нет. Как только общее количество элементов достигнуто, остальная часть файла возвращается, чтобы вы могли повторить процесс, используя конвейеры.

Вот пример того, как запустить его с окончательным выводом:

$ ./script.sh 2 1 file.txt | ./script.sh 2 2 | ./script.sh 1 3
$ tail -n +1 file_*
==> file_1.txt <==
<elem>aaaaaaaa1</elem>
<elem>aaaaaaaa2</elem>

==> file_2.txt <==
<elem>bbbbbbbb
bbbbbbbbb
bbbbbbbbb</elem>
<elem>bbbbbbbb2</elem>

==> file_3.txt <==
<elem>ccccc

cccc</elem>
person Emer    schedule 31.05.2017
comment
ничего себе, я только что понял, что это было задано более 2 лет назад! извините за поздний ответ :Р - person Emer; 01.06.2017