sed 또는 perl을 사용하여 파일의 모든 일치 항목을 열거합니다.

sed 또는 perl을 사용하여 파일의 모든 일치 항목을 열거합니다.

다음 파일이 있습니다.

:~$ cat test
        <Set Id="16">
                <Ver="44" Sniff="no" B2vpnId="" Collision="no">
        </Set>        
        <Set Id="17">
                <Ver="22" Sniff="no" B2vpnId="" Collision="no">
        </Set>

파일에서 B2vpnId 값을 늘려야 하는데 출력에서 ​​이 변경 사항을 가져오는 방법을 찾았습니다.

:~$ i=1;while read -r line; do echo "$line"|sed -e 's/B2vpnId=""/B2vpnId="'"vpn$i"'"/';((i+=1));done <<< "$(cat test|grep B2vpnId=)"
<Ver="44" Sniff="no" B2vpnId="vpn1" Collision="no">
<Ver="22" Sniff="no" B2vpnId="vpn2" Collision="no">

하지만 다른 구성 줄이 많기 ​​때문에 파일 자체에서 이러한 변경을 수행해야 하는데 이를 수행할 방법을 찾을 수 없습니다.

답변1

사용된 perl정규식 수정자는 /e연산자의 대체 부분을 s/search/replace/Perl 코드로 평가합니다.

$ perl -p -e 's/B2vpnId=""/sprintf "B2vpnId=\"vpn%i\"", ++$i/e' test 
        <Set Id="16">
                <Ver="44" Sniff="no" B2vpnId="vpn1" Collision="no">
        </Set>
        <Set Id="17">
                <Ver="22" Sniff="no" B2vpnId="vpn2" Collision="no">
        </Set>

표준 출력으로 출력하는 것이 아니라 디스크의 파일을 변경하려면 Perl의 -i옵션을 사용하십시오.

$i여러 파일을 처리하고 각 파일 다음에 카운터( )를 재설정하려면 ; $i=0 if eof스크립트 끝에 다음을 추가하세요.

$ cp test test2
$ perl -p -e 's/B2vpnId=""/sprintf "B2vpnId=\"vpn%i\"", ++$i/e; $i=0 if eof' test test2
        <Set Id="16">
                <Ver="44" Sniff="no" B2vpnId="vpn1" Collision="no">
        </Set>
        <Set Id="17">
                <Ver="22" Sniff="no" B2vpnId="vpn2" Collision="no">
        </Set>

        <Set Id="16">
                <Ver="44" Sniff="no" B2vpnId="vpn1" Collision="no">
        </Set>
        <Set Id="17">
                <Ver="22" Sniff="no" B2vpnId="vpn2" Collision="no">
        </Set>

해당 문이 없으면 $i=0 if eof테스트된 두 번째 복사본의 B2vpnID는 "vpn3" 및 "vpn4"입니다.

그런데 카운터가 다른 숫자(예: 10)에서 시작하도록 하려면 BEGIN { $i=9 };스크립트 시작 부분에 추가하세요. BEGIN블록은 입력을 읽기 전에 한 번만 실행됩니다. 스크립트의 나머지 부분은 각 입력 줄에 대해 한 번씩 반복적으로 실행됩니다. 그런데 한 번만 실행되는 다른 유형의 코드 블록이 있습니다 man perlsyn.

블록 앞에 컴파일 단계 키워드(예: , , 또는)가 있으면 BEGIN해당 블록 은 END해당 실행 단계에서만 실행됩니다. 자세한 내용은 참조하십시오 .INITCHECKUNITCHECKperlmod

$i늘어난다는 점 기억하세요앞으로매번 사용되므로(스크립트가 using ++$i대신 사용하여 $i++매번 사용할 때마다 값이 증가하므로) 시작 숫자에서 1을 뺍니다.

또한 예를 들어 BEGIN 블록을 사용하는 경우 $i=0 if eofBEGIN 블록과 일치하도록 변경해야 합니다 .$i=9 if eof

$ perl -p -e 'BEGIN { $i=9 };
              s/B2vpnId=""/sprintf "B2vpnId=\"vpn%i\"", ++$i/e;
              $i=9 if eof' test 

또는 이제 BEGIN 블록을 사용하여 $i를 초기화하므로 $i를 사후 증가시킬 수 있습니다(그리고 다른 변수를 시작 값으로 사용하므로 한 곳에서만 변경하면 됩니다).

$ perl -p -e 'BEGIN { $start = 10; $i = $start };
              s/B2vpnId=""/sprintf "B2vpnId=\"vpn%i\"", $i++/e;
              $i = $start if eof' test 

또는 기본값인 1로 설정한 다음만약에첫 번째 인수는 기존 파일이 아닙니다. 첫 번째 인수로 설정하세요.

$ perl -p -e 'BEGIN {
                $start = 1;
                $start = shift unless -f $ARGV[0];
                $i = $start
              };

              s/B2vpnId=""/sprintf "B2vpnId=\"vpn%i\"", $i++/e;

              $i = $start if eof' 10 test* 

답변2

이는 다음과 같은 경우에 더 적합합니다 awk.

$ awk 'BEGIN { c=1 } /B2vpnId/ { sub(/vpnId="/, "vpnId=\"vpn"c,$0); c++ }1' test
        <Set Id="16">
                <Ver="44" Sniff="no" B2vpnId="vpn1" Collision="no">
        </Set>        
        <Set Id="17">
                <Ver="22" Sniff="no" B2vpnId="vpn2" Collision="no">
        </Set>

실제로 파일을 변경하려면(GNU awk):

$ awk -i inplace <rest of command>

참고: 참조고양이에게 쓸모없는 용도;

답변3

가장 쉬운 방법은 출력을 임시 파일로 리디렉션한 다음 임시 파일을 원본 파일 위로 이동하는 것입니다.

그러나 명령줄의 복잡성에 조금 놀랐습니다.

i=1
while read -r line; do
    echo "$line"|sed -e 's/B2vpnId=""/B2vpnId="'"vpn$i"'"/'
    ((i+=1))
done <<< "$(cat test|grep B2vpnId=)"

더 간단한 방법은 다음과 같습니다.

i=1
grep 'B2vpnId=' test |
while read -r line; do 
    echo "$line"|sed -e 's/B2vpnId=""/B2vpnId="'"vpn$i"'"/'
    ((i+=1))
done

그러나 변경되지 않는 줄을 에코해야 하는 경우 grep루프에 넣어야 할 수도 있습니다.

i=1
while read -r line; do 
    if echo "$line" | grep -q 'B2vpnId=' ; then
        echo "$line"|sed -e 's/B2vpnId=""/B2vpnId="'"vpn$i"'"/'
        ((i+=1))
    else
        echo "$line"
    fi
done < test

이는 자체 솔루션을 기반으로 합니다.

관련 정보