我有一个文件,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
我需要附加到每个列表(其中有两个以上)并最终得到如下内容:
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)
我知道如何获取第一个列表的开头和第二个列表的开头(包括)之间的所有内容:
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) {
...
}
我最初发布了一个简化版本,因为
- 我不确定实际文件是否始终遵循这种格式(顶部的注释、变量声明、更多注释、列表定义、函数等)
- 我想找到问题的通用解决方案(将内容附加到文件中间的列表中)
抱歉,如果这有误导性。
答案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
第一个sed
转义任何反斜杠,第二个sed
处理将其转换为第三个(通过)用来处理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
so ,例如 example 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
如果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的格式为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';