2012-01-19 7 views
0

問題 正確な行数を維持しながら、任意の長さ(行数)のテキストをテンプレートに挿入する必要があります。sed:行番号制約付きの柔軟なテンプレート

サンプル・ソース・データ・ファイル:

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%> 

この時点で私が使用してレコードでソースファイル レコードをロードするためにはbashの「マップファイル」を使用します/ ^#end-of-file/regex ...これまでのところとても良いです。 それから、私は各レコードの予測可能な側面を、それらが発生する行 に従って引いてから、一連のsed search replace文を使用して情報を処理します。

ハングアップ 問題が発生する可能性のある「タイトル」レコードの数が不明です。 未知数のタイトルに対応するにはどうすればよく、正確に65行の出力 が出力されますか? <% CUST-の間、

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

、私はこれが割り当てられたスペースの中に挿入することができますどのように、例:

は、タイトルのレコードは常に、8行目から始まる起こる私は簡単に タイトルを引き出すことができることを考えますCTY-ZIP%>と<%STORE-NAME%>をテンプレート内の適切な場所に保存しないでください。これまで

私の考え:
例:

はを通じて顧客情報を送る-first。

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

- 追加タイトルレコード ???

-Then店/位置情報

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

興味があれば、私はこのようなもののためのコードと機能を持っていますが、この記事では、それがあるとして「風」です。 ちょうど次のテキストの位置を維持し、65 *

UPDATE の総行数を維持しながら、タイトルレコードを挿入して助けを必要と私は戦術を変更することを決めました。私はその後、---顧客と店舗情報との間のすべての使用可能な回線用のテンプレートにプレースホルダを作成するつもりです:

  • テストを行がソース
  • にnullの場合yesの場合 - nullが去ると、プレースホルダを置き換えます行末。行番号は維持されます。
  • nullでない場合は、テキストに置き換えて、テンプレートに行番号と行末を保持します。

最終的に、私はPerpleに関するTripleeの提案をもっと近くに見ていく予定です。 Perlのやり方は、私がこのプロジェクトに長時間取り掛かっていれば本当に簡単になり、維持しやすくなります。

+0

パッディングやスクイーズについて質問していますか?物を絞る必要がある場合、私たちは何を削除することができますか?詰め物の場合、詰め物はどこに行きますか? 'sed'は算術演算ではあまり良くありませんが、awkでは出力が65行になるまで改行を追加するのは簡単です。 – tripleee

+0

でもかまいません。パディングよりもタイトルが1つだけの場合... 5以上の場合は、一部を切り取る必要があります。 – Bubnoff

+0

任意の数のタイトルエントリの下にあるものは、まったく同じ行になければなりません。そのため、行を数え、つまみをつけたり、フッターを予想通りに実行できるようにする必要があります。簡単な表示のための味わいのある改行 – Bubnoff

答えて

1

これはあなたのために働くかもしれません:あなたは、より少ない必要以上の所望の数に5を変更した場合

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)にタイトルを絞り出します。

1

これはtitles.txtであなたに関係なく、行数の出力の5行を与える:

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 

使用1ラインの数はあなたが欲しい未満(4この例では5行の出力が発生します)。

+0

で、 'eval()'の提案を見てください。質問には、「タイトルレコードは常に8行目から始まることを考えると、 – potong

+0

@potong:私の 'cat '多かれ少なかれプレースホルダだった。質問から 'sed'コマンドを使うように質問を更新しました。 –

+0

これをテストしようとしています。 – Bubnoff

1

ここでは、Perlフォーマットを使用した簡単な概念証明があります。 Perlに精通していない人は、2つの異なるファイルから値を取得する方法についていくつかの追加的な助けが必要だと思いますが、それはもちろん実行可能です。ここでは、データは単にスクリプト自体に埋め込まれています。

ターミナルウィンドウで試しやすくするため、適切な値(58など)の代わりに$titles形式を5行に設定し、出力が長くなったときに出力が実際に切り捨てられることを実証するために割り当てられた領域よりも大きくなります。

#!/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の使用は非常に醜いですが、私は可能な限り、通常のようなフォーマットを維持したいです。私はそれを避けることができると確信していますが、追加のコード複雑さIMHOを犠牲にしています。

あなたがPerlに精通していない場合、use strictは複雑ですが、実用上必要です。変数をuse varsまたはmyのいずれかで宣言する必要があります。これは、スクリプトを変更しようとすると非常に役立つベストプラクティスです。

<<HEREのドキュメントは、シェルスクリプトのように動作します。それは簡単に複数行の文字列を作成することができます。

x演算子は繰り返し用です。 'string' x 3'stringstringstring'であり、("list") x 3("list" "list" "list")である。ドット演算子は文字列の連結です。つまり"foo" . "bar""foobar"です。

最後に、ファイルハンドルを使用すると、プログラムコードの末尾にある__END__トークンの後にスクリプトファイル自体に任意のデータを入れることができます。標準入力から読み取る場合は、<DATA>の代わりに<>を使用してください。

+0

よく知るperl、but rusty。私はこれを見て、それにショットをつけます。ありがとう! – Bubnoff

関連する問題