編集する

編集する

次のファイルlists.txtがあります。

// stuff at beginning of file

var list1 = new Array();
i = 0;
list1[i++] = 'a';
list1[i++] = 'b';
...
list1[i++] = 'z';

var list2 = new Array();
i = 0;
list2[i++] = 'a';
list2[i++] = 'b';
...
list2[i++] = 'z';

// other stuff at end of file

各リスト(3つ以上があります)に追加し、次のように終了する必要があります。

var list1 = new Array();
i = 0;
list1[i++] = 'a';
list1[i++] = 'b';
...
list1[i++] = 'z';
list1[i++] = 'something new';

var list2 = new Array();
i = 0;
list2[i++] = 'a';
list2[i++] = 'b';
...
list2[i++] = 'z';
list2[i++] = 'another thing';

// other stuff at end of file

私はこれについてしばらく心配してきました。各リストの最後の項目を取得する方法を知っています。

list1_last=$(grep "list1\[i++\]" lists.txt | tail -1)
list2_last=$(grep "list2\[i++\]" lists.txt | tail -1)

最初のリストの先頭と2番目のリストの先頭(含む)の間のすべてのアイテムを取得する方法を知っています。

list1=$(sed -n '/var list1/,/var list2/p' lists.txt)

私はlist2の最初の行なしでlist1を取得できることを知っています。このPerlコード行またはこのクレイジーsedスクリプト

しかし、すべての作品を1つに集めるのに苦労しています。どうすればいいですか?

編集する

追加する追加値は、別のファイル extra-values.txt にあります。たとえば、次のようになります。

list1[i++] = 'something new';
list2[i++] = 'another thing';

両方のファイルをマージしようとしていると言えるようです。

編集2

実際の文書次のように見えます。

// comment
// comment
// ...
var foo = "bar";

// comment
// comment
// ...
var i= 0;

// comment
// comment
// ...
var GoodDomains = new Array();
i=0;
GoodDomains[i++] = "anything.com";  // comment
GoodDomains[i++] = "something.com"; // comment
...
GoodDomains[i++] = "lastthing.com"; // comment
// THIS IS WHERE I WANT TO INSERT SOMETHING

// comment
// comment
// ...
var BadDomains = new Array();
i=0;
BadDomains[i++] = "anything.com";  // comment
BadDomains[i++] = "something.com"; // comment
...
BadDomains[i++] = "lastthing.com"; // comment
// THIS IS WHERE I WANT TO INSERT SOMETHING

// more lists, including GoodHosts, GoodURLs, etc.

// comment
// comment
// ...
for (i in GoodDomains) {
    ...
}

// loop through BadDomains, GoodHosts, GoodURLs, etc.

// comment
// comment
// ...
function IsNumIpAddr(host) {
    ...
}

もともとは単純化されたバージョンを公開しました。

  1. 実際のファイルが常にこの形式に従うかどうかはわかりません(上部のコメント、変数宣言、追加コメント、リスト定義、関数など)。
  2. 問題に対する一般的な解決策を見つけたいです(ファイルの中央にあるリストにコンテンツを追加します)。

誤解を招くと申し訳ありません。

答え1

ファイルを逆にすると、次のようにできます。最初何かを見るとき:

tac lists.txt |
awk -v l1="list1" -v val1="something new" \
    -v l2="list2" -v val2="another thing" '
          index($0, l1"[i++]") && !found1 {
              printf "%s[i++] = \"%s\";\n", l1, val1
              found1 = 1
          }
          index($0, l2"[i++]") && !found2 { 
              printf "%s[i++] = \"%s\";\n", l2, val2
              found2 = 1
          }
          {print}
' |
tac > lists.txt.new

少し退屈しても大丈夫です。

「additional-values.txt」を見逃しました。これは良いです:

tac lists.txt | 
awk '
    NR == FNR {additional[$1] = $0; next}
    $1 in additional && !found[$1] {print additional[$1]; found[$1] = 1}
    {print}
' additional-values.txt - | 
tac > newfile

答え2

範囲を使用しようとしているので、sedこれが可能なアプローチです。あなたの行はadditional-values.txt同じパターンに従います。

KEY[i++] = 'VALUE'; //etc

私が知る限り、各行に

var KEY = new Array();

そして空行


これにより、各行に対して以下を実行するスクリプトadditional-values.txtで処理および変換できます。sed

/^var KEY = new Array();/,/^$/{
/^$/ i\
KEY[i++] = 'VALUE'; // etc
}

つまり、範囲内の/^var KEY = new Array();/,/^$/空の行の前に行を挿入します。KEY[i++] = 'VALUE'; // etcその後、スクリプトを使用して以下を処理しますlists.txt

sed 's/\\/&&/g' additional-values.txt | \
sed 's|^\([^[]*\).*|/^var \1 = new Array();/,/^$/{\
/^$/ i\\\
&\
}|' | sed -f - lists.txt

1 つ目はsedバックスラッシュをエスケープし、2 つ目はsed3 つ目 (パススルー) が処理するスクリプトに変換して処理しますadditional-values.txt。たとえば、サンプルコンテンツは次のようになります。sed-flists.txt
additional-values.txt

GoodDomains[i++] = '^stuff/here/'; \
BadDomains[i++] = '%XYZ+=?\\<>';
GoodNetworks[i++] = '|*{};:\'; // Malware\\
BadDomains[i++] = '\$.|&$@"#"!||';

結果:

sed 's/\\/&&/g' additional-values.txt | \
sed 's|^\([^[]*\).*|/^var \1 = new Array();/,/^$/{\
/^$/ i\\\
&\
}|'

はい

/^var GoodDomains = new Array();/,/^$/{
/^$/ i\
GoodDomains[i++] = '^stuff/here/'; \\
}
/^var BadDomains = new Array();/,/^$/{
/^$/ i\
BadDomains[i++] = '%XYZ+=?\\\\<>';
}
/^var GoodNetworks = new Array();/,/^$/{
/^$/ i\
GoodNetworks[i++] = '|*{};:\\'; // Malware\\\\
}
/^var BadDomains = new Array();/,/^$/{
/^$/ i\
BadDomains[i++] = '\\$.|&$@"#"!||'; 
}

sed -f - lists.txt次に、例のように渡しますlists.txt

// Counter Variable to initalize the arrays.
var i= 0;

var GoodDomains = new Array();
i=0;
GoodDomains[i++] = 'aba.com'; // Phish - 2010-02-05

var GoodNetworks = new Array();
i=0;
GoodNetworks[i++] = '10.0.0.0, 255.0.0.0';  // NRIP
// GoodNetworks[i++] = "63.140.35.160"; // DNSWCD 2o7

var BadDomains = new Array();
i=0;
BadDomains[i++] = '.0catch.com'; // AdServer - 2009-06-16

//var BadDomains = new Array();

ランニング:

sed 's/\\/&&/g' additional-values.txt | \
sed 's|^\([^[]*\).*|/^var \1 = new Array();/,/^$/{\
/^$/ i\\\
&\
}|' | sed -f - lists.txt

出力:

// Counter Variable to initalize the arrays.
var i= 0;

var GoodDomains = new Array();
i=0;
GoodDomains[i++] = 'aba.com'; // Phish - 2010-02-05
GoodDomains[i++] = '^stuff/here/'; \

var GoodNetworks = new Array();
i=0;
GoodNetworks[i++] = '10.0.0.0, 255.0.0.0';  // NRIP
// GoodNetworks[i++] = "63.140.35.160"; // DNSWCD 2o7
GoodNetworks[i++] = '|*{};:\'; // Malware\\

var BadDomains = new Array();
i=0;
BadDomains[i++] = '.0catch.com'; // AdServer - 2009-06-16
BadDomains[i++] = '%XYZ+=?\\<>';
BadDomains[i++] = '\$.|&$@"#"!||'; 

//var BadDomains = new Array();

gnu sed交換を希望して処理する場合:

sed -E 's|^([^[]*).*|/^var \1 = new Array();/,/^$/{/^$/ i\\\n&\
}|' <(sed 's/\\/&&/g' additional-values.txt) | sed -f - lists.txt

答え3

入力ファイルのリストが空白行で区切られている場合は、レコード区切り文字(「行」定義)を連続した改行文字に設定するために使用できるツールがあります。たとえば、Perlの場合(代替ファイルがというファイルにあると仮定additions):

perl -ne 'BEGIN{## Open the additions file
                open($fh,"additions"); 
                while(<$fh>){ 
                  ## Get the name of the current list
                  /list./; 
                  ## save this replacement in the %f hash
                  $f{$&}=$_;
                }
                ## Set the record separator to consecutive newlines.
                $/="\n\n";
               }
          ## Now that the BEGIN{} block is finished, process the
          ## input file.

         ## Does this line match "list."? 
         if(/list./){
            chomp; ## remove trailing newlines. 
            ## Add the addition to this "line"
            $_.= "\n$f{$&}\n\n"; 
          } 
         ## print each input line
         print ' file 

上記の式は次のように単純化できます。

perl -ne 'BEGIN{open($fh,"additions"); while(<$fh>){/list./;$f{$&}=$_;}$/="\n\n";}
         if(/list./){chomp;$_.= "\n$f{$&}\n\n"; }; print ' file 

答え4

リストが次のように新しい行で区切られていると仮定すると、

var list1 = new Array();
i = 0;
list1[i++] = 'a';
list1[i++] = 'b';
list1[i++] = 'z';

var list2 = new Array();
i = 0;
list2[i++] = 'a';
list2[i++] = 'b';
list2[i++] = 'z';\n

extra-lists.txtが次の場合:

list1[i++] = 'something new';
list2[i++] = 'another thing';

その後、このbash / sedスクリプトは目的の出力を生成します。

#! /bin/bash
a="lists.txt"
b="additional-values.txt"
while read line; do
    list=$(expr match "$line" '\(.*\[\)')   
    list=${list::-1}
    sed -i "/$list\[i++\]/{:loop; n; /^$/{s/^$/$line\n/; b}; b loop;}" $a
done < $b

これは、 extra-values.txt の各行を読み取り、その行の部分文字列を [(additional-lists.txt が name[i++]... 形式であると仮定する) まで取得することによってこれを行います。例: "list1[" リスト名を取得するには、最後の文字を削除します。次に、リスト名と一致するsedスクリプトを起動し(bash変数を使用するには二重引用符を使用します)、空白行に達すると終了するループを開始します。最後に、空の行を追加された値の行(および改行)に置き換えます。 -i オプションは内部編集を意味します。

出力:

 $ cat lists.txt
 var list1 = new Array();
 i = 0;
 list1[i++] = 'a';
 list1[i++] = 'b';
 list1[i++] = 'z';
 list1[i++] = 'something new';

 var list2 = new Array();
 i = 0;
 list2[i++] = 'a';
 list2[i++] = 'b';
 list2[i++] = 'z';
 list2[i++] = 'another thing';

関連情報