问题
I have a pom.xml
file and I want to replace the version inside any of the dependency
nodes from 0.1-SNAPSHOT
to a different version (let's say NEW-VERSION
), the only restriction I have is that the replacement should be done only if the groupId
matches a particular text, lets say: com.company.xyz
.
That being said, let's say this is the dependencies
section of my pom.xml
:
<dependencies>
<dependency>
<groupId>com.company.xyz</groupId>
<artifactId>xyz-xx-utils</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.ibm.xyz</groupId>
<artifactId>xyz</artifactId>
<version>56.1</version>
</dependency>
</dependencies>
After applying the sed command I want it to look like:
<dependencies>
<dependency>
<groupId>com.company.xyz</groupId>
<artifactId>xyz-xx-utils</artifactId>
<version>NEW-VERSION</version>
</dependency>
<dependency>
<groupId>com.ibm.xyz</groupId>
<artifactId>xyz</artifactId>
<version>56.1</version>
</dependency>
</dependencies>
Here is what I have tried without any success:
newVersion="NEW-VERSION"
sed -i "s/\(<dependency>\)\(<groupId>com.company.xyz</groupId>\)\(<artifactId>.*\</artifactId>\)\(<version>0.1-SNAPSHOT</version>\)\(</dependency>\)/\1\2\3$newVersion\5/" pom.xml
I was wondering if the reason why this does not work is because my text has multiple lines, so I researched a little bit but I did not understand the syntax used to work with multiple lines (some N
thing).
Btw, I am including this piece of code in a bash file that performs other operations, that is why I want to do this using sed or any other "tool" that is bash compatible.
回答1:
gnu-awk with custom RS
(record separator) suites this better:
awk -v RS="</dependency>" 'index($0, "<groupId>com.company.xyz</groupId>"){
sub(/0\.1-SNAPSHOT/, "NEW-VERSION")} RT{$0 = $0 RT} 1' file
Awk command breakup
-v RS="</dependency>" # sets input record separator as </dependency>
index($0, "<groupId>...") # for lines that have give string
sub(/0\.1-SNAPSHOT/, "NEW-VERSION") # replace 0.1-SNAPSHOT by NEW-VERSION
1 # default action to print the line
In short this awk command breaks input data into records as section containing multiple lines before </dependency>
and then checks for presence of desired groupId
using index
function and replaces the text using sub
function.
Output:
<dependencies>
<dependency>
<groupId>com.company.xyz</groupId>
<artifactId>xyz-xx-utils</artifactId>
<version>NEW-VERSION</version>
</dependency>
<dependency>
<groupId>com.ibm.xyz</groupId>
<artifactId>xyz</artifactId>
<version>56.1</version>
</dependency>
</dependencies>
回答2:
This is a sed solution – a little more unwieldy than awk, but not horribly so. If you store this in a file, say, sedscr
:
/<dependency>/ {
:start
N
/<\/dependency>$/!b start
/<groupId>com.company.xyz<\/groupId>/ {
s/\(<version>\)0\.1-SNAPSHOT\(<\/version>\)/\1NEW-VERSION\2/
}
}
You can run it with sed -i sedscr pom.xml
. This is how it works:
/<dependency>/ { # If the line matches "<dependency>"
:start # Label to branch to
N # Append next line to pattern space
# If the pattern space does not end with "</dependency>", branch to start
/<\/dependency>$/!b start
# We now have the complete <dependency> element in the pattern space
# If the groupId element matches "com.company.xyz"
/<groupId>com.company.xyz<\/groupId>/ {
# Substitute the version for "NEW-VERSION"
s/\(<version>\)0\.1-SNAPSHOT\(<\/version>\)/\1NEW-VERSION\2/
}
}
Your sed didn't work because you try to match across newlines, but sed only has one line at a time in its pattern space – unless you start using commands like N
("Next"). Even when you do have multiple lines in pattern space, you have to account for newlines and match them with \n
(and take care of whitespace and so on).
You could use this in a Bash script as follows:
#!/bin/bash
new_version='NEW-VERSION'
sed '/<dependency>/ {
:start
N
/<\/dependency>$/!b start
/<groupId>com.company.xyz<\/groupId>/ {
s/\(<version>\)0\.1-SNAPSHOT\(<\/version>\)/\1'"$new_version"'\2/
}
}' pom.xml
Quoting like this avoids potential trouble when the sed commands are not within single quotes; only $new_version
is in double quotes to allow for interpolation.
回答3:
I would recommend using maven properties which are clear and accidentally easy to process with sed search and replace.
So pom.xml will look like:
<properties>
<xyz-xx-utils.version>2.0</xyz-xx-utils.version>
</properties>
<dependencies>
<dependency>
<groupId>com.company.xyz</groupId>
<artifactId>xyz-xx-utils</artifactId>
<version>${xyz-xx-utils.version}</version>
</dependency>
</dependencies>
Command line to change the version will be:
sed -i.bak "s/<xyz-xx-utils.version>.*<\/xyz-xx-utils.version>/<xyz-xx-utils.version>NEW-VERSION<\/xyz-xx-utils.version>/g" $pomfile
回答4:
The following awk programs, which have been tested with gawk and mawk, simplify and generalize the awk program using RS given elsewhere on this page. By using printf, they also ensure spacing is preserved.
(a) simplification
awk -v RS="</dependency>" '/<groupId>com.company.xyz<\/groupId>/ {
sub(/0\.1-SNAPSHOT/, "NEW-VERSION")} {printf "%s", $0 RS}'
(b) simplification with generalization
awk -v groupId="com.company.xyz" -v RS="</dependency>" '
$0 ~ "<groupId>" groupId "</groupId>" {
sub("<version>.*</version>", "<version>NEW-VERSION</version>")
}
{printf "%s", $0 RS}'
来源:https://stackoverflow.com/questions/34957616/is-it-possible-to-use-sed-to-replace-dependenciess-version-in-a-pom-file