问题
This self-answered question addresses the scenario originally described in Increment version number in file:
A version number embedded in a text file is to be incremented.
Sample text-file content:
nuspec{
id = XXX;
version: 0.0.30;
title: XXX;
For instance, I want embedded version number 0.0.30
updated to 0.0.31
.
The line of interest can be assumed to match the following regex: ^\s+version: (.+);$
Note hat the intent is not to replace the version number with a fixed new version, but to increment the existing version.
Ideally, the increment logic would handle version strings representing either [version]
(System.Version) or [semver]
(System.Management.Automation.SemanticVersion) instances, ranging from 2 - 4 components; e.g.:
1.0
1.0.2
1.0.2.3
-[version]
format (up to 4 numeric components)1.0.2-preview2
-[semver]
format (up to 3 numeric components), optionally with a-
-separated preview label1.0.2-preview2+001
- ditto, additionally with a+
-separated build label
回答1:
In PowerShell [Core] (v6.1+), a concise solution is possible:
$file = 'somefile.txt'
(Get-Content -Raw $file) -replace '(?m)(?<=^\s+version: ).+(?=;$)', {
# Increment the *last numeric* component of the version number.
# See below for how to target other components.
$_.Value -replace '(?<=\.)\d+(?=$|-)', { 1 + $_.Value }
} | Set-Content $file
Note:
* In PowerShell [Core] 6+, BOM-less UTF-8 is the default encoding; use -Encoding
with Set-Content
if you need a different encoding.
* By using -Raw
, the command reads the entire file into memory first, which enables writing back to that same file in the same pipeline; however, there is a slight risk of data loss if writing back to the input file gets interrupted.
* -replace
invariably replaces all substrings that match the regex.
* Inline regex option (?m)
ensures that ^
and $
match the start and end of individual lines, which is necessary due to Get-Content -Raw
reading the entire file as a single, multi-line string.
Note:
For simplicity, text-based manipulation of the version string is performed, but you could also cast
$_.Value
to[version]
or[semver]
(PowerShell [Core] v6+ only) and work with that.
The advantage of the text-based manipulation is the concise ability to retain all other components of the input version string as-is, without adding previously unspecified ones.The above relies on the -replace operator's ability to perform regex-based string substitutions fully dynamically, via a script block (
{ ... }
) - as explained in this answer.The regexes use look-around assertions (
(?<=...)
and(?=...)
) so as to ensure that only the part of the input to be modified is matched.- Only the
(?<=^\s+version: )
and(?=;$)
look-arounds are specific to the sample file format; adjust these parts as needed to match the version number in your file format.
- Only the
The above increment's the input version's last numeric component. To target the various version-number components, use the following inner regex instead:
Increment the major number (e.g.,
2.0.9
->3.0.9
):'2.0.9' -replace '\d+(?=\..+)', { 1 + [int] $_.Value }
The minor number:
'2.0.9' -replace '(?<=^\d+\.)\d+(?=.*)', { 1 + [int] $_.Value }
The patch / build number (3rd component;
2.0.9
->2.0.10
):'2.0.9' -replace '(?<=^\d+\.\d+\.)\d+(?=.*)', { 1 + [int] $_.Value }
The last / revision number, as above, whatever it is, even if followed by a pre-release label (e.g.,;
2.0.9.10
->2.0.9.11
or7.0.0-preview2
->7.0.1-preview2
):'2.0.9.10' -replace '(?<=\.)\d+(?=$|-)', { 1 + [int] $_.Value }
Note: If the targeted component doesn't exist, the original version is returned as-is.
In Windows PowerShell, where -replace
doesn't support script-block-based substitutions, you can use the switch statement with the -File
and -Regex
options instead:
$file = 'someFile.txt'
$updatedFileContent =
switch -regex -file $file { # Loop over all lines in the file.
'^\s+version: (.+);$' { # line with version number
# Extract the old version number...
$oldVersion = $Matches[1]
# ... and update it, by incrementing the last component in this
# example.
$components = $oldVersion -split '\.'
$components[-1] = 1 + $components[-1]
$newVersion = $components -join '.'
# Replace the old version with the new version in the line
# and output the modified line.
$_.Replace($oldVersion, $newVersion)
}
default { # All other lines.
# Pass them through.
$_
}
}
# Save back to file. Use -Encoding as needed.
$updatedFileContent | Set-Content $file
来源:https://stackoverflow.com/questions/60651450/increment-a-version-number-contained-in-a-text-file