Bash

將一些內容附加到文件中的每個列表

  • August 21, 2015

我有一個文件,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 的第一行的情況下使用這個 Perl one-liner這個瘋狂的 sed script來獲得 list1 。

但是我很難把所有的部分放在一起。我該怎麼做?

編輯

我要附加的附加值在另一個文件 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. 我不確定實際文件是否總是遵循這種格式(頂部的註釋、變數聲明、更多註釋、列表定義、函式等)
  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.txtso ,例如 sample 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

引用自:https://unix.stackexchange.com/questions/205540