편집하다

편집하다

다음과 같은 파일인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. 실제 파일이 항상 이 형식을 따르는지는 잘 모르겠습니다(상단의 주석, 변수 선언, 추가 주석, 목록 정의, 함수 등).
  2. 문제에 대한 일반적인 해결책을 찾고 싶습니다(파일 중간에 있는 목록에 콘텐츠 추가).

오해의 소지가 있다면 죄송합니다.

답변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-flists.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';

관련 정보