![편집하다](https://linux55.com/image/65679/%ED%8E%B8%EC%A7%91%ED%95%98%EB%8B%A4.png)
다음과 같은 파일인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 스크립트.
하지만 모든 조각을 하나로 모으는 데 어려움을 겪고 있습니다. 어떻게 해야 합니까?
편집하다
추가하려는 추가 값은 다른 파일 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
첫 번째는 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
그런 다음 예와 같이 전달하십시오 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';