2016-04-18 2 views
0

У меня есть два текстовых файла, каждый из которых содержит блок текста, разделенный пустыми строками. Блоки различаются по размерам.Объединить два текстовых файла по блоку

# ::id 10 
# ::snt Yes ! 
...multiple lines of unstructured data from file 1... 

# ::id 11 
# ::snt said Lion . 
...multiple lines of unstructured data from file 1... 

# ::id 12 
# ::snt Yes yes ! 
...multiple lines of unstructured data from file 1... 

# ::id 13 
# ::snt said Tiger . 
...multiple lines of unstructured data from file 1... 

и аналогично другим

# ::id 10 
# ::snt No ! 
...multiple lines of unstructured data from file 2... 

# ::id 11 
# ::snt said Monkey . 
...multiple lines of unstructured data from file 2... 

# ::id 12 
# ::snt No no ! 
...multiple lines of unstructured data from file 2... 

# ::id 13 
# ::snt said Donkey . 
...multiple lines of unstructured data from file 2... 

Я хочу, чтобы объединить два блока, но сортировать их по # ::id. Кроме того, мне нужно обеспечить порядок блоков данных file1 перед блоками данных file2. Таким образом, конечный результат должен быть примерно таким:

# ::id 10 
# ::snt Yes ! 
...multiple lines of unstructured data from file 1... 

# ::id 10 
# ::snt No ! 
...multiple lines of unstructured data from file 2... 

# ::id 11 
# ::snt said Lion . 
...multiple lines of unstructured data from file 1... 

# ::id 11 
# ::snt said Monkey . 
...multiple lines of unstructured data from file 2... 

# ::id 12 
# ::snt Yes yes ! 
...multiple lines of unstructured data from file 1... 

# ::id 12 
# ::snt No no ! 
...multiple lines of unstructured data from file 2... 

# ::id 13 
# ::snt said Tiger . 
...multiple lines of unstructured data from file 1... 

# ::id 13 
# ::snt said Donkey . 
...multiple lines of unstructured data from file 2... 

Как это сделать? Все, что будет работать bash, sed, awk

+1

'awk' позволяет вам использовать регулярное выражение как разделитель записи (RS). Вы можете прочитать файл в массиве и отсортировать его с помощью 'asort', например. –

+0

Не могли бы вы предоставить синтаксис? Мой 'awk' немного ржавый. Проблема в том, что я хочу _merge_ двух текстовых файлов в один. Как мне это сделать? – Sudhi

+0

Основная идея - прочитать оба файла в массиве и отсортировать его. Однако если файлы очень большие, это не будет действительной стратегией. –

ответ

1
$ awk -v RS= -v ORS='\n\n' 'NR==FNR{a[NR]=$0;next} {print a[FNR] ORS $0}' file1 file2 
# ::id 10 
# ::snt Yes ! 

# ::id 10 
# ::snt No ! 

# ::id 11 
# ::snt said Lion . 

# ::id 11 
# ::snt said Monkey . 

# ::id 12 
# ::snt Yes yes ! 

# ::id 12 
# ::snt No no ! 

# ::id 13 
# ::snt said Tiger . 

# ::id 13 
# ::snt said Donkey . 

выше считывает содержимое файлов один пункт в то время, в массив a[] где абзацы блоки текста, разделенных цепей пустых строк (любезно предоставлено значение RS). Когда он читает первый файл, он просто сохраняет их в массиве a[1..number of paragraphs], а затем после того, как он прочитает весь файл1 в a[], когда он читает второй файл, он сначала печатает соответствующий абзац из файла1 (a[paragraph number]), а затем текущий абзац из файла2.

+1

Спасибо! Это сработало. Я уточнил свой вопрос с дополнительной информацией. Но я думаю, вы поняли этот вопрос. – Sudhi

+0

Если у вас есть время, я очень благодарен за объяснение того, как это работает. Всегда приятно учиться :-) – Sudhi

+1

Я добавил объяснение в конце. Я рекомендую книгу «Эффективное программирование Awk», 4-е издание, Арнольдом Роббинсом. –

1

Say: awk -f merge.awk file1 file2

BEGIN { RS="" } 
{ ARR[NR] = $0 } 
END { 
    n = asort(ARR); 
    for (i = 1; i <= n; i++) 
     print ARR[i]; 
} 
+0

Это может сортировать больше, чем предполагалось, поскольку оно будет использовать все содержимое абзаца при сортировке. Вы можете сохранить по id в 'ARR' (и добавить к значению), чтобы этого избежать. –

+0

Спасибо! Очень полезно. Однако функция asort испортила порядок файлов. Я хочу первый блок из файла1 и второй блок из файла 2. Но он возвращается в обратном порядке. Я попробовал переупорядочить файл, но не повезло. Похоже, функция 'asort' сортирует массив как строку.Поэтому, если блок из 'file2' меньше _stringwise_, тогда он появится первым. Любые указатели на то, как это исправить? – Sudhi

+0

err, любые указатели на то, как хранить как блок, так и идентификатор? Могу ли я обработать запись дважды? – Sudhi

0

Вы можете достичь этого, используя sed и sort:

sed '/# ::id/N;s/\n/ /;/^$/d' file1 file2 | sort -s -n -k3,3 | sed 's/\(# ::snt.*\)/\n\1\n/' 

Первая sed часть присоединяется к линии следующей строки вместе с один из которых содержит # ::id и удаляет пустую строку.

Результат затем сортируется по идентификационному номеру выражения # ::id xx (третий параметр).

В конце концов линии разрезают в 2 частях, где # ::snt найден

+0

Спасибо! Однако после строки '# :: snt' существует несколько строк (неструктурированных). Как я могу захватить все эти? – Sudhi

+0

Я обновил свой вопрос с дополнительной информацией. – Sudhi

0

это соответствует записи по номерам идентификаторов в случае, если они не совпадают в обоих файлах

$ awk -F'\n' -v RS= 'NR==FNR{a[$1]=$0; next} 
          {printf "%s\n\n%s\n\n",a[$1],$0}' file1 file2 

# ::id 10 
# ::snt Yes ! 
...multiple lines of unstructured data from file 1... 

# ::id 10 
# ::snt No ! 
...multiple lines of unstructured data from file 2... 

# ::id 11 
# ::snt said Lion . 
...multiple lines of unstructured data from file 1... 

# ::id 11 
# ::snt said Monkey . 
...multiple lines of unstructured data from file 2... 

# ::id 12 
# ::snt Yes yes ! 
...multiple lines of unstructured data from file 1... 

# ::id 12 
# ::snt No no ! 
...multiple lines of unstructured data from file 2... 

# ::id 13 
# ::snt said Tiger . 
...multiple lines of unstructured data from file 1... 

# ::id 13 
# ::snt said Donkey . 
...multiple lines of unstructured data from file 2... 

может быть повышена, чтобы поймать недостающие записи в file2, а также.

Смежные вопросы