Awk или Sed: аннотация файла - PullRequest
1 голос
/ 06 января 2011

Привет, мой ТАК друг, мой вопрос:

Спецификация: аннотировать поля FILE_2 в соответствующую позицию FILE_1.
A поле помечено и, следовательно, идентифицировано парой разделителей .

Я сделал эту работу на python, прежде чем я знал awk и sed, с парой сотен строк кода. Теперь я хочу увидеть, насколько мощными и эффективными могут быть awk и sed. Покажите мне какой-нибудь шедевр awk или sed, пожалуйста!

Пары разделителей можно настроить в FILE_3, но давайте предположим, что первый разделитель в паре равен
'Marker (number i) start', другой -
'Marker (number i) done'

Пример:
| ----------------- file_1 ------------------ |
текст текст текст
текст блабла
Marker_1_start
Marker_1_done
любой текст
между блаблами
Marker_2_start
Marker_2_done
текстовый текст

| ----------------- file_2 ------------------ |
Marker_1_start
11
1111
Marker_1_done
Marker_2_start
2222
22
Marker_2_done

Ожидаемый результат:
| ----------------- file_out ------------------ |
текст текст текст
текст блабла
Marker_1_start
11
1111
Marker_1_done
любой текст
между блаблами
Marker_2_start
2222
22
Marker_2_done
текстовый текст

Ответы [ 3 ]

3 голосов
/ 06 января 2011
awk '
    FNR==NR && /Marker_.*_done/  {sep = ""; next}
    FNR==NR && /Marker_.*_start/ {marker = $0; next}
    FNR==NR {marker_text[marker] = marker_text[marker] sep $0; sep = "\n"; next}
    1 {print}
    /Marker_.*_start/ {print marker_text[$0]}
' file_2 file_1
2 голосов
/ 06 января 2011

Есть несколько способов подойти к этому.Я предполагаю, что FILE_2 меньше, чем FILE_1 и имеет разумный размер.

#!/usr/bin/awk -f
FNR == NR {
    if ($0 ~ /^Marker.*start$/) {
        flag = 1
        idx = $0
        next
    }
    if ($0 ~ /^Marker.*done$/) {
        flag = 0
        nl = ""
        next
    }
    if (flag) lines[idx] = lines[idx] nl $0
    nl = "\n"
    next
}
{
    print
    if (lines[$0]) print lines[$0]
}

Для его запуска:

./script.awk FILE_2 FILE_1
0 голосов
/ 06 января 2011

Теперь я хочу увидеть, насколько мощным и эффективный awk и sed может быть

Для такого типа проблем очень эффективно. Я уверен, что мой код можно еще уменьшить.

#!/bin/bash

awk '
  FNR == NR {
     if ($0 ~ /Marker_1_start/){m1=1;next}
     if ($0 ~ /Marker_2_start/){m2=1;next}
     if ($0 ~ /Marker_1_done/){m1=0}
     if ($0 ~ /Marker_2_done/){m2=0}

     if(m1){a[i++]=$0}
     if(m2){b[j++]=$0}
  }
  FNR != NR {
     if ($0 ~ /Marker_1_start/){print;n1=1}
     if ($0 ~ /Marker_2_start/){print;n2=1}
     if ($0 ~ /Marker_1_done/){n1=0}
     if ($0 ~ /Marker_2_done/){n2=0}

     if(n1)
       for (k = 0; k < i; k++)
         print a[k]
     else if(n2)
       for (l = 0; l < j; l++)
         print b[l]
     else
       print
  }'  ./file_2 ./file_1

выход

$ ./filemerge.sh
text text text
text blabla
Marker_1_start
11
1111
Marker_1_done
any text
in between blabla
Marker_2_start
2222
22
Marker_2_done
text text
...