I have a Jenkinsfile which analyses some local artifactory server for new versions of the parent and dependencies. When I confirm that there is a new version, I want to replace the old version with a new one.
so given a pom.xml containing this dependency:
<dependency>
<groupId>abcde</groupId>
<artifactId>xyz</artifactId>
<version>1.2.4</version>
</dependency>
... and assume that there is a newer version 1.3.5 of abcde.xyz ...
I would like to update that with the following sed command:
sed -i '/<dependency>/,/<\/dependency>/{
/<groupId>abcde<\/groupId>/{
/<artifactId>xyz<\/artifactId>/{
s/<version>1.2.4<\/version>/<version>1.3.5<\/version>/
}
}
}' pom.xml
If I create a pom.xml either containing the above xml or only the above xml and execute this statement, the file is modified, but nothing changes. removing the -i
flag basically dumps the file 1:1 to stdout - what am I missing?
expected output:
<dependency>
<groupId>abcde</groupId>
<artifactId>xyz</artifactId>
<version>1.3.5</version>
</dependency>
(In the jenkinsfile it is parameterized and escaped like below, but since the basic statement is not working, please focus on that.)
sh """
sed -i '/<dependency>/,/<\\/dependency>/{
/<groupId>${groupId}<\\/groupId>/{
/<artifactId>${artifactId}<\\/artifactId>/{
s/<version>${version}<\\/version>/<version>${targetVersion}<\\/version>/
}
}
}' pom.xml
"""
Directly in a shell if you do sed 's/${groupId}/foo/'
the groupId
variable won't be expanded as it's inside single quotes. That might also occur when you wrap it in sh """ ... """
as you're doing for whatever you're running it within ("jenkinsfile"?), I don't know.
/<dependency>/,/<\/dependency>/{ foo }
means "for each of the lines from /<dependency>/
to /<\/dependency>/
do foo
. So you're isolating the block of lines you're interested in but then foo
is still applied 1 line at a time within that block. You're then doing /<groupId>abcde<\/groupId>/
which matches that line and then trying to do /<artifactId>xyz<\/artifactId>/
within that line, but <artifactId>
doesn't exist on the same line as <groupId>
and so will never do anything.
You can do this easily, more robustly, and without duplicating any of the block start/end expressions with awk, e.g. using a small state machine with GNU awk for -i inplace
(which I assume you have since you're using GNU sed):
$ awk -i inplace -v grp='abcde' -v art='xyz' -v oldVer='1.2.4' -v newVer='1.3.5' '
$1 == "</dependency>" { s=0 }
$1 == "<dependency>" { s=1 }
(s==1) && index($0, "<groupId>" grp "</groupId>") { s=2 }
(s==2) && index($0, "<artifactId>" art "</artifactId>") { s=3 }
(s==3) && index($0, "<version>" oldVer "</version>") {
$0 = "<version>" newVer "</version>"
}
{ print }
' pom.xml
$ cat pom.xml
<dependency>
<groupId>abcde</groupId>
<artifactId>xyz</artifactId>
<version>1.3.5</version>
</dependency>
In addition to doing what you asked for that solves the problem you would have had with sed being unable to do literal string comparisons and so requiring you to escape all regexp metachars, sed delimiters, and backreferences, see Is it possible to escape regex metacharacters reliably with sed.