我正在尝试编写一段bash脚本,用于递增给定的版本号。
{major}.{minor}.{revision}
例如。1.2.13
有没有一种好的方法可以使用sed或awk轻松提取这三个数字,以便我可以增加{revision}号并输出完整的版本号字符串。
$ v=1.2.13
$ echo "${v%.*}.$((${v##*.}+1))"
1.2.14
$ v=11.1.2.3.0
$ echo "${v%.*}.$((${v##*.}+1))"
11.1.2.3.1
这是它的工作原理:
字符串被分成两部分。
${v%.*}
${v##*.}
第一部分按原样打印,后跟一个普通点和通过shell算术扩展增加1的最后一部分:$((x+1))
使用纯 Bash 数组的方法:
version='1.2.33'
a=( ${version//./ } ) # replace points, split into array
((a[2]++)) # increment revision (or other part)
version="${a[0]}.${a[1]}.${a[2]}" # compose new version
IFS
并使用 "${a[*]}"
。谢谢,我能够很好地利用它! - Florian我更喜欢使用“cut”命令来处理这种情况。
major=`echo $version | cut -d. -f1`
minor=`echo $version | cut -d. -f2`
revision=`echo $version | cut -d. -f3`
revision=`expr $revision + 1`
echo "$major.$minor.$revision"
我知道这不是最简单的方法,但对我而言,这是最容易理解和阅读的方法...
另一种Shell方式(展示了总是有多种方法来搞定这些东西的事实...):
$ echo 1.2.3 | ( IFS=".$IFS" ; read a b c && echo $a.$b.$((c + 1)) )
1.2.4
所以,我们可以这样做:
$ x=1.2.3
$ y=`echo $x | ( IFS=".$IFS" ; read a b c && echo $a.$b.$((c + 1)) )`
$ echo $y
1.2.4
Awk使这变得非常简单:
echo "1.2.14" | awk -F \. {'print $1,$2, $3'}
将打印出1 2 14。
标志 -F 指定分隔符。
如果您想保存其中一个值:
firstVariable=$(echo "1.2.14" | awk -F \. {'print $1'})
echo | awk
重复执行。 - David W.major.minor
,可以使用以下命令获取:echo "1.2.14" | awk -F \. '{version=$1"."$2; print version}'
将会打印出1.2
。 - Antônio Medeiros我使用shell自带的单词分割功能,类似于
oIFS="$IFS"
IFS=.
set -- $version
IFS="$oIFS"
尽管由于字母或日期后缀以及其他令人烦恼的不一致部分,您需要注意版本号的问题。完成此操作后,位置参数将设置为$version
的组件:
$1 = 1
$2 = 2
$3 = 13
($IFS
是一组单个字符,而不是字符串,所以这不能用于多字符字段分隔符,尽管您可以使用 IFS=.-
来在 .
或 -
上进行拆分。)
$IFS
是shell用于执行自身字段(“单词”)拆分的内容;我正在保存原始值(空格、制表符、换行符),并将其设置为“.”,然后使用set
强制$version
进行单词拆分。我将在答案中详细说明。 - geekosaurset -- $version
用$version字段替换命令行参数,该字段由句点拆分。因此,这三个部分现在是$1、$2、$3。如果您不想使用set,可以尝试使用以下命令:echo $version | read major minor revision
。它不够紧凑,但不会影响您仍然可能使用的命令行参数。 - David W.while
循环可能在子shell中运行,可能会产生令人惊讶的结果(例如,循环中的变量设置不会被脚本的其余部分看到)。http://stackoverflow.com/questions/6245246/translating-bin-ksh-date-conversion-function-into-bin-sh - geekosaurwhile
行并将其删除了。这不用一分钟就完成了。这是将输入导入 while read 循环的老习惯了。实际上,我放置的内容在 BASH 中不起作用,但在我使用的 Kornshell 中可以正常工作。它与 BASH 完全兼容,除非它不能正常工作。为了使其在 bash 中正常工作,您必须将 $version
作为此处文档放置。 - David W.echo $version | read major minor revision
而不是set -- $version
的想法,但那根本没有起作用。 - smithfarm受到jlliagre的回答启发,我制作了自己的版本,支持仅提供主要版本号的版本号。jlliagre的版本会将1 -> 1.2而非2。
这个版本适用于两种风格的版本号:
function increment_version()
local VERSION="$1"
local INCREMENTED_VERSION=
if [[ "$VERSION" =~ .*\..* ]]; then
INCREMENTED_VERSION="${VERSION%.*}.$((${VERSION##*.}+1))"
else
INCREMENTED_VERSION="$((${VERSION##*.}+1))"
fi
echo "$INCREMENTED_VERSION"
}
increment_version 1 -> 2
increment_version 1.2 -> 1.3
increment_version 1.2.9 -> 1.2.10
increment_version 1.2.9.101 -> 1.2.9.102
我很惊讶没有人建议使用grep。
以下是如何从文件名中获取完整版本(不限于x.y.z的长度)的方法:
filename="openshift-install-linux-4.12.0-ec.3.tar.gz"
find -name "$filename" | grep -Eo '([0-9]+)(\.?[0-9]+)*' | head -1
# 4.12.0
对 fgm 的解决方案进行小变化,使用内置的 read
命令将字符串拆分为数组。请注意,IFS
变量的作用域仅限于 read
命令(因此无需存储和恢复当前的 IFS
变量)。
version='1.2.33'
IFS='.' read -r -a a <<<"$version"
((a[2]++))
printf '%s\n' "${a[@]}" | nl
version="${a[0]}.${a[1]}.${a[2]}"
echo "$version"