次のファイル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
ファイルを逆にすると、次のようにできます。最初何かを見るとき:
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 つ目はsed
3 つ目 (パススルー) が処理するスクリプトに変換して処理しますadditional-values.txt
。たとえば、サンプルコンテンツは次のようになります。sed
-f
lists.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';