简体   繁体   中英

Replace and increment tag value in XML file with sed

I'm working in Linux and in my XML file I'd like to replace <version> tag value by another string, when the number value will be incremented by 1 one. For example if I have XML file like this:

<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.rm.core</groupId>
    <artifactId>rm-dt-agr</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>rm-dt-agr</name>
</project>

I'd like to replace 0.0.1-SNAPSHOT in tag <version> by 0.0.2-SNAPSHOT If it's 0.0.2-SNAPSHOT value I'd like to replace it with 0.0.3-SNAPSHOT and so on...

I tried to use "sed" command but without success.

This is one of those situation where you should really use a tool meant for processing XML rather than trying to shoehorn a bash solution. That being said, for simple tag substitutions with minimal format gymnastics involved, bash can work quite well.

For any situation where you are looking to change a line in a file, you will need to write the changes to a new or temp file and then copy to replace the original. (while theoretically, since you are only changing a single character and not adjusting the line-length, you really can just write the changes to the new file, but beware)

The difficulty here is you have a 5 character sting , with 3 digits separated by '.' (periods) instead of a simple number. No matter what tool you choose, you will have some string manipulation to do to parse down to the point where you know the value you need to increment. Then once found, you must preserve the format (meaning you must account for any time an increment causes your value to change from a single-digit number to a two-digit number) Presumably, you must adjust the value of the next digit if your increment causes the single digit to overflow.

There are a couple of approaches you can take. You can manually create a new file that reflects the changes by writing all lines, except the one that changes, to the new file without any modification. Of course, write the changed line as well. The second would be to parse the file to get the line that needs changing, do the calculation to increment the number and then use sed to do the substitution.

The following takes the manual approach and writes a complete new file. Look over it, give it a try, and remember -- you are better served finding an XML tool to parse and modify XML...

#!/bin/bash

[ -z $1 ] && {  ## validate input file given
    printf "error: insufficient input. usage: %s filename\n" "${0//*\//}"
    exit 1
}

[ -r $1 ] || {  ## validate input file readable
    printf "error: file not found/readable\n" "$1"
    exit 1
}

ifile="$1"      ## set input/output filename, truncate output file
ofile="${2:-newxml.xml}"
:> "$ofile"

while IFS= read -r line; do                     ## for each line
    text="${line// /}"                          ## remove leading spaces
    if [ "${text//>*/}" = '<version' ]; then    ## match version tag 
        nspcs=$((${#line} - ${#text}))          ## save # spaces removed
        value="${text#<version>}"               ## strip tags from ends
        value="${value%</version>}"
        nstr="${value%-*}"                      ## separate number string
        label="${value#*-}"                     ## from text -SNAPSHOT
        IFS=. read v1 v2 v3 <<<"$nstr"          ## read separate numbers
        [ -z $v1 -o -z $v2 -o -z $v3 ] && {     ## validate
            printf "error invalid value: '%s'\n" "$value"
            continue
        }
        v3=$((v3 + 1))          ## increment by 1
        [ $v3 -eq 10 ] && {     ## adjust remaining if 10
            v3=0
            v2=$((v2 + 1))
        }
        [ $v2 -eq 10 ] && {
            v2=0
            v1=$((v1 + 1))
        }                       ## output updated line to new file
        printf "%*s%s\n" $nspcs " " "<version>$v1.$v2.$v3-$label</version>" >> "$ofile"
    else
        printf "%s\n" "$line" >> "$ofile"   ## write other lines unchanged
    fi
done <"$ifile"

exit 0

Input File

$ cat dat/file.xml
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.rm.core</groupId>
    <artifactId>rm-dt-agr</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>rm-dt-agr</name>
</project>

Example Use

$ bash xmlchgvalue.sh dat/file.xml dat/new.xml

Output File

$ cat dat/new.xml
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.rm.core</groupId>
    <artifactId>rm-dt-agr</artifactId>
    <version>0.0.2-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>rm-dt-agr</name>
</project>

Verification

$ diff dat/file.xml dat/new.xml
8c8
<     <version>0.0.1-SNAPSHOT</version>
---
>     <version>0.0.2-SNAPSHOT</version>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM