次のようなファイル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
これらのリストのそれぞれに追加する必要があり(2つ以上あります)、次のようになります。
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スクリプト 。
しかし、私はすべてのピースをまとめるのに苦労しています。どうすればよいですか?
追加したい追加の値は、別のファイル、additional-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) {
...
}
もともと簡略版を投稿したのは
これが誤解を招く場合は申し訳ありません。
sed
の範囲で試しているので、これを行うための1つの可能な方法があります。 _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
_
最初のsed
はバックスラッシュをエスケープし、2番目のsed
は_additional-values.txt
_を処理して、3番目の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
_
ファイルを逆にすると、次の行を追加できます最初何かが表示されたとき:
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
入力ファイルのリストが空白行で区切られている場合は、レコード区切り文字(「行」を定義するもの)を連続する改行に設定できるツールを使用できます。たとえば、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
あなたのリストがこのような新しい行で区切られているとすると
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
そして、additional-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
これを行うには、additional-values.txtの各行を読み取り、その行の部分文字列を[(additional-lists.txtの形式は[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';
Awkのレコード区切り文字RS
を次のように設定して使用します:リストの最後の行と次の空白行。
仕組み:
最初は、RS
は\n
(デフォルト)— 1番目の引数で指定された入力ファイルの場合:additional-values.txt
最初のファイルを読み込んだ直後に、awk
はRS
の値を2番目の引数の値に変更します。
2番目のファイルlists.txt
、3番目に名前が付けられ、argには2番目のargによって定義されたRS
があります
行1:追加の値の配列を作成する
line 2:分割の最初のフィールドは現在のリストのキーです— RT
経由(RS
によるテキスト)
line :print record + record-separator(less one \n
)+追加の値
awk 'RS == "\n" { addval[$1] = addval[$1] $0 "\n"; next }
{ split(RT,crskey)
print $0 gensub(/\n/,"","",RT) addval[ crskey[1] ]
}' additional-values.txt \
RS='[^[\n]+[[]i[+][+][]] = [^;\n]+;\n\n' \
lists.txt
私はついにうまくいくものを思いついた:
# print from beginning of file to "var list1" (exclusive)
sed "/var list1/,\$d" lists.txt > merged.txt
# print from "var list1" to last member of array
lastlist1=$(grep -n "list1\[i++\]" lists.txt | tail -1 | cut -f1 -d:)
sed -n "/var list1/,$(echo $lastlist1)p" lists.txt >> merged.txt
grep "^list1" additional-values.txt >> merged.txt
# print from "var list2" to last member of array
lastlist2=$(grep -n "list2\[i++\]" lists.txt | tail -1 | cut -f1 -d:)
sed -n "/var list2/,$(echo $lastlist2)p" lists.txt >> merged.txt
grep "^list2" additional-values.txt >> merged.txt
# do this for list3, list4,... listn
# print from last member of listn (exclusive) to end of file
sed "1,$(echo $lastlistn)d" lists.txt >> merged.txt
これはかなり退屈で、おそらく改善できるでしょうが、少なくとも私はそれを理解しています。