sed, awk или perl: соответствие диапазона шаблонов, выведите 45 строк, затем добавьте разделитель записей - PullRequest
2 голосов
/ 23 марта 2012

У меня есть файл, содержащий записи, разделенные шаблоном / # matchee /. Эти записи имеют различную длину ... скажем, 45 - 75 строк. Они должны ALL иметь 45 строк и при этом поддерживать разделитель записей. Записи могут быть из разных отделов, название отдела указывается в строке 2 после пустой строки. Таким образом, разделитель записей можно рассматривать как просто / ^ # matchee / или / ^ matchee /, за которым следует \ n. Существует Deluxe редакция этой проблемы и Walmart редакция ...

ИЗБРАННОЕ ИЗДАНИЕ

Извлечение каждой записи по диапазону шаблонов, чтобы я мог сортировать записи по отделам. Например, с сед

sed -n '/^DEPARTMENT NAME/,/^#matchee/{p;}' mess-o-records.txt

Затем выведите только первые 45 строк каждой записи в файле для соответствия ограничение 45 строк.

Наконец, убедитесь, что результат содержит разделитель записи в строке 45.

WALMART EDITION

То же, что и выше, но вместо использования диапазона просто используйте разделитель записей.

СТАТУС

Моя попытка это может прояснить, что я пытаюсь сделать.

sed -n -e '/^DEPARTMENT-A/,/^#matchee/{p;}' -e '45q' -e '$s/.*/#matchee/' mess-o-records.txt

Конечно, это не работает, потому что sed работает с целым файлом в каждой команде. Мне нужно, чтобы он работал с каждым диапазоном , а не с целым файлом .

ОБРАЗЕЦ ВХОДА - 80 строк (усечено для пробела)

<blank line>
DEPARTMENT-A
Office space 206
Anonymous, MI 99999

Harold O Nonymous
Buckminster Abbey
Anonymous, MI 99999

item A     Socket B     45454545
item B     Gizmo Z      76767676
<too many lines here>
<way too many lines here>  


#matchee

ОБРАЗЕЦ ВЫХОДА - теперь только 45 строк

<blank line>
DEPARTMENT-A
Office space 206
Anonymous, MI 99999

Harold O Nonymous
Buckminster Abbey
Anonymous, MI 99999

item A     Socket B     45454545
item B     Gizmo Z      76767676
<Record now equals exactly 45 lines>  
<yet record delimiter is maintained>

#matchee

ОБНОВЛЕНИЕ РАЗЪЯСНЕНИЯ

Мне никогда не понадобится больше, чем первые 40 строк, если это облегчит задачу. Может быть, процесс будет:

  • Шаблон (ы) совпадений
  • Вывести первые 40 строк.
  • Подушка подходящей длины. Например, 45 строк.
  • Снова включить разделитель тэков. Например, # матчи

Я думаю, что это было бы более гибко - т.е. может обрабатывать записи короче, чем 45 строк.

Вот рифф, основанный на примере Perl @ Borodin's:

my $count = 0;
$/ = "#matchee";    

while (<>) {
    if (/^REDUNDANCY.*DEPT/) {
        print;
        $count = 0;
    }   
    else {
        print if $count++ < 40; 
        print "\r\n" x 5; 
        print "#matchee\r\n";
    }   
}

Это добавляет 5 новых строк к каждой записи + шаблон разграничения / # matchee /. Так что это неправильно - но это иллюстрирует то, что я хочу.

Печать 40 строк на основе разделителя - pad - tack delimiter on.

Ответы [ 4 ]

2 голосов
/ 23 марта 2012

Я думаю, я понимаю, что вы хотите. Не уверен насчет бита около тянуть каждую запись по диапазону паттернов . За #matchee всегда следует пустая строка, а затем строка отдела? Так на самом деле запись № 2?

Этот фрагмент Perl делает то, что, как я понимаю, вам нужно.

Если вы предпочитаете, вы можете поместить входной файл в командную строку и сбросить вызов open. Тогда цикл должен быть while (<>) { ... }.

Дайте нам знать, если это правильно, и что еще вам нужно от этого.

use strict;
use warnings;

open my $fh, '<', 'mess-o-records.txt' or die $!;

my $count = 0;

while (<$fh>) {
  if (/^#matchee/) {
    print;
    $count = 0;
  }
  else {
    print if $count++ < 45;
  }
}
1 голос
/ 26 марта 2012

Я знаю, что этот ответ уже был принят, но я решил опубликовать пример awk для всех, кто заинтересован. Это не 100%, но это делает работу.

Примечание Число строк, чтобы вы могли убедиться, что скрипт работает должным образом. Удалите i, из print i, current[i], чтобы удалить номера строк.

dep.awk

BEGIN { RS = "#matchee\n\n" }

$0 ~ /[a-zA-Z0-9]+/ {
    split($0, current, "\n")
    for (i = 1; i <= 45; i++) {
        print i, current[i];
    }
    print "#matchee\n"
}

В этом примере вы начинаете сценарий, устанавливая разделитель записей ( RS ) на "# matchee \ n \ n" . Есть две новые строки, потому что первая оканчивает строку, в которой встречается #matchee, а вторая - сама по себе пустая строка.

Совпадение подтверждает, что запись содержит буквы или цифры, которые должны быть действительными. Вы также можете проверить, что матч начинается с 'DEPARTMENT-', но это не удастся, если будет случайный перевод строки. Проверка содержимого является самым безопасным маршрутом. Поскольку при этом используется блочная запись (то есть, DEPARTMENT-A - #matchee), вы можете либо пропустить $ 0 через awk или sed снова, либо использовать функцию разбиения awk и пройти через 45 строк. В awk массивы не индексируются нулями.

Функция печати включает новую строку, поэтому блок заканчивается только print "#matchee\n" вместо двойного \n в переменной разделителя записей.

Вы также можете добавить тот же скрипт awk в скрипт bash и изменить количество строк и разделитель полей. Конечно, вы должны добавить проверки и еще много чего, но вот начало:

dep.sh

#!/bin/bash
# prints the first n lines within every block of text delimited by splitter
splitter=$1
numlines=$2

awk 'BEGIN { RS="'$1'\n\n" }
$0 ~ /[a-zA-Z0-9]+/ {
    split($0, current, "\n")
    for(i=1;i<='$numlines';i++) {
        print i, current[i]
    }
    print "'$splitter'", "\n"
}' $3

Сделать скрипт исполняемым и запустить его.

./dep.sh '#matchee' 45 input.txt > output.txt

Я добавил эти файлы в гист, чтобы вы могли также проверить вывод

0 голосов
/ 24 марта 2012

Решение TXR (http://www.nongnu.org/txr)

В целях иллюстрации, используя поддельные данные, я сокращаю требование с 40 строк до 12 строк.Мы находим записи, начинающиеся с названия отдела, разделенные #matchee.Мы дампим их, разделив их не более чем на 12 строк, снова добавив #matchee.

@(collect)
@  (all)
@dept
@  (and)
@    (collect)
@line
@    (until)
#matchee
@    (end)
@  (end)
@(end)
@(output)
@  (repeat)
@{line[0..12] "\n"}
#matchee
@  (end)
@(end)

Здесь переменная dept ожидается из опции командной строки -D, ноКонечно, код может быть изменен для принятия его в качестве аргумента и вывода использования, если оно отсутствует.

Запуск на примере данных:

$ txr -Ddept=DEPARTMENT-A trim-extract.txr mess-o-records.txt 
DEPARTMENT-A
Office space 206
Anonymous, MI 99999

Harold O Nonymous
Buckminster Abbey
Anonymous, MI 99999

item A     Socket B     45454545
item B     Gizmo Z      76767676

<too many lines here>
#matchee

Пустые строки перед DEPARTMENT-Aушли, и есть ровно 12 строк, которые включают в себя одну строку из <too many ...> мусора.

Обратите внимание, что семантика @(until) такова, что #matchee исключен из собранного материала,Поэтому правильно безоговорочно добавить его в предложение @(output).Эта программа будет работать, даже если запись окажется короче 12 строк до того, как будет найден #matchee.

Она не будет соответствовать записи, если #matchee не найден.

0 голосов
/ 24 марта 2012

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

D="DEPARTMENT-A" M="#matchee"
sed '/'"$D/,/$M"'/{/'"$D"'/{h;d};H;/'"$M"'/{x;:a;s/\n/&'"$M"'/45;tb;s/'"$M"'/\n&/;ta;:b;s/\('"$M"'\).*/\1/;p};d}' file

Пояснение:

  • Фокус на диапазон линий /DEPARTMENT/,/#matchee/
    • В начале диапазона переместить пробел (PS) в пробел (HS) и удалить PS /DEPARTMENT/{h;d}
    • Все последующие строки в диапазоне добавляются к HS и удаляются H....;d
    • В конце диапазона: /#matchee/
      • Обмен на HS x
      • Проверка на 45 строк в диапазоне и при успешном добавлении #matchee на 45-й строке s/\n/&#matchee/45
      • Если предыдущая замена прошла успешно, переходите к метке b. tb
      • Если предыдущая замена была неудачной, вставьте перевод строки до #matchee s/'"$M"'/\n&/, увеличив длину короткой записи до 45 строк.
      • Разветвление для метки a и проверка на 45 строк и т. ta
      • Заменить первое вхождение #matchee до конца строки своим собственным. s/\('"$M"'\).*/\1/, сокращая длинную запись до 45 строк.
      • Печать диапазона записей. p
  • Все записи вне диапазона проходят без изменений.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...