如果 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 for -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 文件”的意思)common,您可以执行以下操作(假设您正在使用bash, 和 GNU gawk):

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示例(标签需要首先修复,因为dependencies未关闭)并使用xmlstarlet

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

编辑

groupId考虑到仅对version包含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)

相关内容