sed: гибкий шаблон с ограничением номера строки - PullRequest
0 голосов
/ 19 января 2012

Проблема Мне нужно вставить текст произвольной длины (количество строк) в шаблон при сохранении точного количества строк.

Пример файла исходных данных:

You have a hold available for pickup as of 2012-01-13:
Title: Really Long Test Title Regarding Random Gibberish. Volume 1, A-B, United States
 and affiliated territories, United Nations, countries of the world
Author: Barrel Roll Morton
Title: How to Compromise Free Speech Using Everyday Tools. Volume XXVI
Author: Lamar Smith
#end-of-record
You have a hold available for pickup as of 2012-01-13:
Title: Selling Out Democracy For Fun and Profit. Volume 1, A-B, United States
Author: Lamar Smith
Copy: 12
#end-of-record

Образец шаблона (упрощенно для краткости):

<%CUST-NAME%>
<%CUST-ADDR%>
<%CUST-CTY-ZIP%>

<%TITLES GO HERE%>

<%STORE-NAME%>
<%STORE-ADDR%>
<%STORE-CTY-ZIP%>

На этом этапе я использую 'mapfile' bash для загрузки записи исходного файла по записи, используя / ^ # end-of-file /регулярное выражение ... пока все хорошо.Затем я извлекаю предсказуемые аспекты каждой записи в соответствии со строкой, в которой они появляются, затем обрабатываю информацию, используя серию операторов поиска и замены.

Зависание Таким образом, проблема заключается в неизвестном количестве «титульных» записей, которые могут возникнуть.Как я могу разместить неизвестное количество заголовков и всегда иметь вывод точно 65 строк?

Учитывая, что записи заголовков всегда происходят, начиная со строки 8, я могу легко извлечь заголовки с помощью:

 sed -n '8,$p' test-match.txt

Однако, как я могу вставить это в выделенное пространство, например, между <% CUST-CTY-ZIP%> и <% STORE-NAME%>, не выталкивая информацию о магазине из шаблона в шаблон?

Моя идея пока:

- сначала отправьте информацию о клиенте через:Пример.

sed 's/<%CUST-NAME%>/Benedict Arnold/' template.txt

- Добавить титульные записи ???

- Затем информация о магазине / местоположении

sed 's/<%STORE-NAME%>/Smith's House of Greasy Palms/' template.txt

У меня есть код и функции для этого материала, если интересноно этот пост "ветреный", как это.Просто нужна помощь по вставке записей заголовков, сохраняя положение следующего текста и поддерживая общее количество строк 65. *

ОБНОВЛЕНИЕ Я решил сменить тактику.Я собираюсь создать заполнители в шаблоне для всех доступных строк между покупателем и информацией о магазине --- тогда:

  • Проверить, является ли строка нулевой в источнике
  • , если да -- заменить заполнитель на ноль, оставляя конец строки.Сохранение номера строки.
  • если не равно нулю - снова замените его на текст, сохраняя номер строки и окончания строк в шаблоне.

В конце концов, я планирую потратить некоторое время на более внимательное рассмотрениеПредложение Трипли относительно Perl.Путь Perl действительно выглядит проще и проще в обслуживании, если я собираюсь застрять в этом проекте в долгосрочной перспективе.

Ответы [ 3 ]

1 голос
/ 19 января 2012

Это даст вам пять строк вывода независимо от количества строк в titles.txt:

sed -n '$s/$/\n\n\n\n\n/;8,$p' test-match.txt | head -n 5

Другая версия:

sed -n '8,$N; ${s/$/\n\n\n\n\n/;s/\(\([^\n]*\n\)\{4\}\).*/\1/p}' test-match.txt

Используйте на одну строку меньше необходимого количества строк (в этом примере 4 приведет к выводу 5 строк).

1 голос
/ 21 января 2012

Вот краткое доказательство концепции с использованием форматов Perl. Если вы не знакомы с Perl, я думаю, вам понадобится дополнительная помощь в получении значений из двух разных файлов, но, конечно, это вполне выполнимо. Здесь данные просто встраиваются в сам скрипт.

Я установил формат $titles на 5 строк вместо правильного значения (58 или что-то в этом роде), чтобы упростить его использование в окне терминала и продемонстрировать, что вывод действительно обрезается, когда он больше выделенного пространства.

#!/usr/bin/perl                                                                 

use strict;
use warnings;

use vars (qw($cust_name $cust_addr $cust_cty_zip $titles                        
    $store_name $store_addr $store_cty_zip));

my $fmtline = '@' . '<' x 78;
my $titlefmtline = '^' . '<' x 78;
my $empty = '';
my $fmt = join ("\n$fmtline\n", 'format STDOUT = ',
                '$cust_name', '$cust_addr', '$cust_cty_zip', '$empty') .
    ("\n$titlefmtline\n" . '$titles') x 5 . #58                                 
    join ("\n$fmtline\n", '', '$empty',
          '$store_name', '$store_addr', '$store_cty_zip');
#print $fmt;                                                                    
eval "$fmt\n.\n";

titles = <<____HERE;
Title: Really Long Test Title Regarding Random Gibberish. Volume 1, A-B, United States
 and affiliated territories, United Nations, countries of the world
Author: Barrel Roll Morton
Title: How to Compromise Free Speech Using Everyday Tools. Volume XXVI
Author: Lamar Smith
____HERE
# Preserve line breaks -- ^<< will fill lines, but preserves line breaks on \r  
$titles =~ s/\n/\r\n/g;

while (<DATA>) {
    chomp;
    ($cust_name, $cust_addr, $cust_cty_zip, $store_name, $store_addr, $store_cty_zip)
        = split (",");
    write STDOUT;
}
__END__
Charlie Bravo,23 Alpa St,Delta ND 12345,Spamazon,98 Spamway,Atlanta GA 98765

Использование $empty для получения пустой строки довольно уродливо, но я хотел сохранить формат как можно более регулярным. Я уверен, что этого можно избежать, но за счет дополнительной сложности кода ИМХО.

Если вы не знакомы с Perl, use strict - это сложность, но практическая необходимость; это требует, чтобы вы объявили свои переменные либо с помощью use vars или my. Это лучшая практика, которая очень помогает, если вы пытаетесь внести изменения в сценарий.

Здесь документы с <<HERE работают как в скриптах оболочки; позволяет легко создавать многострочные строки.

Оператор x предназначен для повторения; 'string' x 3 равно 'stringstringstring' и ("list") x 3 равно ("list" "list" "list"). Оператор точки - это конкатенация строк; то есть "foo" . "bar" - это "foobar".

Наконец, файловый дескриптор DATA позволяет вам помещать произвольные данные в сам файл скрипта после токена __END__, который сигнализирует об окончании программного кода. Для чтения со стандартного ввода используйте <> вместо <DATA>.

1 голос
/ 19 января 2012

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

cat <<! >titles.txt
> 1
> 2
> 3
> 4
> 5
> 6
> 7
> Title 1
> Title 2   
> Title 3
> Title 4
> Title 5
> Title 6
> !
cat <<! >template.txt
> <%CUST-NAME%>
> <%CUST-ADDR%>
> <%CUST-CTY-ZIP%>
> 
> <%TITLES GO HERE%>
> 
> <%STORE-NAME%>
> <%STORE-ADDR%>
> <%STORE-CTY-ZIP%>
> !
sed '1,7d;:a;$!{N;ba};:b;G;s/\n[^\n]*//5g;tc;bb;:c;s/\n/\\n/g;s|.*|/<%TITLES GO HERE%>/c\\&|' titles.txt | 
sed -f - template.txt
<%CUST-NAME%>
<%CUST-ADDR%>
<%CUST-CTY-ZIP%>

Title 1
Title 2
Title 3
Title 4
Title 5

<%STORE-NAME%>
<%STORE-ADDR%>
<%STORE-CTY-ZIP%>

Это добавляет / сжимает заголовки до 5 строк (s/\n[^\n]*//5g), если вы хотите меньше или больше, измените 5 на желаемое число.*

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...