n+2줄에 특정 문자열이 포함된 경우 일치하는 문자열을 바꾸는 방법

n+2줄에 특정 문자열이 포함된 경우 일치하는 문자열을 바꾸는 방법

예를 들어 행 n+2(버전 행에 com.icc.id.version이 포함되어 있음)인 경우 com.icc.id를 "abc"로 바꿉니다. 다른 것이라면 교체하지 마십시오. 이는 "common" 폴더의 모든 하위 디렉터리에 있는 모든 pom 파일에 대해 작동합니다.

<groupId>com.icc.id</groupId>
<artifactId>abc</artifactId>
<version>${project.version}</version>
<groupId>com.icc.id</groupId>
<artifactId>ifd</artifactId>
<version>${com.icc.id.version}</version>

답변1

이는 필요한 것 이상이지만 나중에 기록으로 더 많은 작업을 수행하는 데 도움이 될 수 있습니다.

$ cat tst.awk
BEGIN { numLines = 3 }
{
    lineNr = (NR - 1) % numLines + 1
    rec[lineNr] = $0
}
lineNr == numLines {
    if ( rec[3] ~ /com\.icc\.id\.version/ ) {
        sub(/com\.icc\.id/,"abc",rec[1])
    }
    for (lineNr=1; lineNr<=numLines; lineNr++) {
        print rec[lineNr]
    }
    delete rec
}

$ awk -f tst.awk file
(groupId)com.icc.id(/groupId)
(artifactId)abc(/artifactId)
(version)${project.version}(/version)
(groupId)abc(/groupId)
(artifactId)ifd(/artifactId)
(version)${com.icc.id.version}(/version)

모든 하위 디렉터리의 모든 ".pom" 파일에 대해 이 작업을 수행하려면 "pom 파일"이 이와 같은 확장자를 가지고 있고 다음에 대해 GNU awk를 사용한다고 가정합니다 -i inplace.

find . -name '*.pom' -exec awk -i inplace -f tst.awk {} +

답변2

n번째 행이 일치하면 n번째 행과 n+1번째 행을 예약 상태로 저장합니다. n+2번째 항목을 읽고 지정된 내용이 있는지 확인합니다. 게임이 끝난 후 리콜은 보류되고 abc로 대체됩니다.

 $ sed -ne '
     />com\.icc\.id</!bp
     N;h;n
     /\<com\.icc\.id\.version\>/{
         x;s/>com\.icc\.id<\(.*\n\)/>abc<\1/;x
    }
     x;G;:p;p
 ' inp.pom

답변3

파일이 메모리에 들어갈 만큼 작은 경우 다음을 수행할 수 있습니다.

$ awk '{lines[NR]=$0}END{for(i in lines){ if(lines[i] ~ /com\.icc\.id/ && lines[i+2] ~ /com\.icc\.id\.version/){gsub("com\\.icc\\.id","abc",lines[i])} print lines[i]}}' file 
(groupId)com.icc.id(/groupId)
(artifactId)abc(/artifactId)
(version)${project.version}(/version)
(groupId)abc(/groupId)
(artifactId)ifd(/artifactId)
(version)${com.icc.id.version}(/version) 

또는 좀 더 읽기 쉽게:

$ awk '{
        lines[NR]=$0
       }
       END{
            for(i in lines){ 
                if(lines[i] ~ /com\.icc\.id/ && 
                   lines[i+2] ~ /com\.icc\.id\.version/){
                        gsub(/com\.icc\.id/,"abc",lines[i])
                } 
            print lines[i]
            }
       }' file 
(groupId)com.icc.id(/groupId)
(artifactId)abc(/artifactId)
(version)${project.version}(/version)
(groupId)abc(/groupId)
(artifactId)ifd(/artifactId)
(version)${com.icc.id.version}(/version) 

디렉터리 및 하위 디렉터리에 있는 확장자를 가진 모든 파일 에 적용하려면 .pom("pom 파일"이 의미하는 것이라고 가정합니다) 다음을 수행할 수 있습니다( , 및 GNU 를 common사용한다고 가정 ).bashgawk

shopt -s globstar
tmpFile=$(mktemp)
for file in common/**/*.pom; do
    awk '{
    lines[NR]=$0
   }
   END{
        for(i in lines){ 
            if(lines[i] ~ /com\.icc\.id/ && 
               lines[i+2] ~ /com\.icc\.id\.version/){
                    gsub(/com\.icc\.id/,"abc",lines[i])
            } 
        print lines[i]
        }
   }' "$file" > "$tmpFile" && mv "$tmpFile" "$file"
   done

답변4

원래 예제를 사용하고 (태그가 닫히지 않았 xml으므로 먼저 수정해야 함 ) 다음을 사용하십시오.dependenciesxmlstarlet

xmlstarlet ed -N "x=http://maven.apache.org/POM/4.0.0" -u "//x:dependency[x:version[contains(text(), 'com.icc.version')]]/x:groupId" -v "BANANA" data.xml

편집하다

groupIdversion포함된 위치 com.icc.versiongroupId포함되지 않은 위치 만 변경해야 하는 이중 제약을 고려하여 com.icc.id다음은 해당 노드만 선택하고 교체해야 합니다.

xmlstarlet ed -N "x=http://maven.apache.org/POM/4.0.0" -u "//x:dependency[x:version[contains(text(), 'com.icc.version')]]/x:groupId[not(contains(text(), 'com.icc.id'))]" -v 'BANANA' data.xml

또는 노드의 전체 텍스트 groupIDcom.icc.id

xmlstarlet ed -N "x=http://maven.apache.org/POM/4.0.0" -u "//x:dependency[x:version[contains(text(), 'com.icc.version')]]/x:groupId[text() !='com.icc.id']" -v 'BANANA' data.xml

@terdon의 루프가 globstar파일을 찾고 출력을 stdout검사할 수 있습니다. 파일을 영구적으로 변경하려면 .pom명령에 이 옵션을 포함하십시오.-L

xmlstarlet ed -L -N  etc.....

입력하다

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <dependencies>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
        </dependency>
        <dependency>
            <groupId>com.icc.id</groupId>
            <artifactId>solution-commons</artifactId>
            <version>${com.icc.id.version}</version>
        </dependency>
        <dependency>
            <groupId>com.icc.banana</groupId>
            <artifactId>application-common</artifactId>
            <version>${com.icc.version}</version>
        </dependency>
        <dependency>
            <groupId>com.icc.id</groupId>
            <artifactId>application-common</artifactId>
            <version>${com.icc.banana}</version>
        </dependency>
    </dependencies>
</project>

산출

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <dependencies>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
    </dependency>
    <dependency>
      <groupId>com.icc.id</groupId>
      <artifactId>solution-commons</artifactId>
      <version>${com.icc.id.version}</version>
    </dependency>
    <dependency>
      <groupId>BANANA</groupId>
      <artifactId>application-common</artifactId>
      <version>${com.icc.version}</version>
    </dependency>
    <dependency>
      <groupId>com.icc.id</groupId>
      <artifactId>application-common</artifactId>
      <version>${com.icc.banana}</version>
    </dependency>
  </dependencies>
</project>

하나경고하다이 점에 대해서. xmlstarlet이해에 따라 다르 namespace므로 namespace모든 파일에서 동일하다면 문제 없습니다. 다르다면 각 파일을 물어보고 결정하여 namespace변수로 전달해야 합니다.

ns=$(grep -Po "(?<=xmlns=\")[^\"]*" data.xml)

관련 정보