n+2行に特定の文字列が含まれている場合に一致する文字列を置き換える方法

n+2行に特定の文字列が含まれている場合に一致する文字列を置き換える方法

たとえば、行 n+2 (バージョン行に com.icc.id.version が含まれている) の場合、com.icc.id を "abc" に置き換えます。それ以外の場合は交換しないでください。これは、「共通」フォルダのすべてのサブディレクトリにあるすべての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ファイル」が意味すると仮定します)commonbashgawk

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

またはノードのフルgroupIDテキスト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[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)

関連情報