2012-07-25 2 views
1

Боюсь, что я не эксперт ни в одном из перечисленных трех инструментов, поэтому я прошу вас всех.получить подраздел текстового файла с использованием awk, sed или grep

У меня есть большой текстовый файл, который можно разбить на несколько разделов, каждый из которых имеет заголовок ABC и нижний колонтитул &&. Типичный файл будет выглядеть следующим образом:

ABC 

... 

<ID> 
123 

... 

&& 

ABC 

... 

<ID> 
124 

... 

&& 

Мне нужно извлечь раздел, основанный на данном ID, например, если ID=123, я хотел бы выход быть:

ABC 

<ID> 
123 

&& 

Где представляет собой случайные данные между ABC<ID> и между 123 и &&. Фактически ID, 123, является переменной.

Я считаю, что выполнение awk '/ABC/,/\&\&/' работает в поиске каждого подраздела, но я не знаю, как получить подраздел, соответствующий правильному идентификатору. Заранее благодарю за любую помощь.

Редактировать: Уточненный вопрос и образец ввода.

ответ

0

Это может работать для вас (GNU SED):

id=123 
sed '/^ABC/,/^&&/{/^ABC/{h;d};H;/^&&/!d;g;/<ID>\n'"$id"'/p};d' file 

Альтернативный метод:

sed ':a;$bb;N;/^ABC/!D;/&&$/!ba;:b;/^ABC.*<ID>\n'"$id"'.*&&$/p;d' file 
+0

Как и решение @slitvinov, ваш работает хорошо, если в текстовом файле есть только один раздел, который начинается с ' ABC' и заканчивается символом '&&'. Типичный текстовый файл будет иметь несколько разделов, однако каждый с другим ID. – Alex

+0

@Alex это должно извлекать только раздел, содержащий входной идентификатор, независимо от нескольких разделов. – potong

0

В СЭД можно сделать так:

sed -i ' /ABC/,/&&/ !{d} ' FILE 

Это будет держать все контексты между ABC и & &.

+0

Извините за неоднозначность. Мое намерение состоит в том, чтобы _retrieve_ подраздел с заголовком 'ABC' и нижний колонтитул' && 'и правильный идентификатор, а не вставлять идентификационную строку. Каждый подраздел текстового файла имеет другой идентификатор. – Alex

+0

Спасибо. Теперь понятно, и решил это. – alinsoar

0

Использование: awk -v id=123 -f foo.awk foo.txt

foo.awk

$0=="ABC",$0=="&&"{ 
    # store everything in data 
    # ternary operation to avoid leading "\n" 
    data=data?(data "\n" $0):$0 
} 


id_flag { 
    # this is a string after "<ID>" 
    if (id==$1) { 
     print_flag = 1 
    } 
    id_flag = 0 
} 

$0=="<ID>"{ 
    # prepare to read id 
    id_flag = 1 
} 

$0=="&&"{ 
    if (print_flag) { 
     print data 
     print_flag = 0 
    } 
    data = "" 
} 
+0

Я думаю, что мой вопрос был немного расплывчатым. Средний текстовый файл, который у меня есть, будет содержать несколько разделов, каждый из которых начинается с 'ABC' и заканчивается' $$$$'. Я считаю, что это решение работает только для текстового файла с одним разделом, как описано. – Alex

+0

Конец с '&&', скорее. – Alex

1

Это решение предполагает, что ваш входной файл состоит исключительно из ABC ... <ID> ... && секций, возможно, разделенных пустыми строками.

ПРИМЕНЕНИЕ:awk -f foo.awk ID=123 input_file

foo.awk:

#!/usr/bin/awk -f 
BEGIN { 
    RS = "\n&&\n"; 
    ORS = RS; 
} 

match($0, "<ID>\n" ID "\n") { 
    sub(/^\n/,"",$0); 
    print $0; 
} 

Если /usr/bin/awk соответствует вашим AWK и вы делаете foo.awk исполняемым вы можете назвать это непосредственно: ./foo.awk ID=123 input_file

Этот код разбивает ваш вход на записи по каждому && на одной строке.
Затем он ищет запись для

<ID> 
your_id 

и печатает его, если он находит совпадение.

sub(/^\n/,"",$0); просто исключает пустые строки между разделами.

Вы также можете иметь это в одной строке:

awk 'BEGIN{ID=124;RS="\n&&\n";ORS=RS};match($0, "<ID>\n" ID "\n") {sub(/^\n/,"",$0);print $0;}' input_file 
+0

Прохладный раствор! Я хотел бы сделать его более идиоматических и добавить регулярное выражение для решения ' \ N123 \ п &&': 'BEGIN { ПРС = RS = "\ п && \ п" } матч ($ 0, " \ п" ID«(\ n | $) ") { gsub (/^\ n /," ") print }' – slitvinov

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