如何在 bash 中增加字符串末尾的数字?

How can I increment a number at the end of a string in bash?

提问人:DDisciple 提问时间:4/17/2019 最后编辑:DDisciple 更新时间:6/21/2019 访问量:4477

问:

基本上,我需要创建一个传递参数的函数,并且我需要更新数字,例如参数将是

version_2,在函数之后,它会将其更改为version_3

只是递增 1

在 java 中,我只会创建一个新字符串,然后抓取最后一个字符更新一个并附加,但不确定如何在 bash 中执行此操作。

updateVersion() {
  version=$1
}

前缀可以是任何内容,例如,它可以是 dog12 或 dog_12,并且始终有一个要更新的数字。

更新后,它将分别是 dog13 或 dog_13。

巴什

评论

0赞 Charles Duffy 4/17/2019
这个数字总是在 之后吗?_
0赞 choroba 4/17/2019
您确定您的 Java 解决方案吗? 不应该更新到 ,对吧?version_19version_110
0赞 DDisciple 4/17/2019
@CharlesDuffy 是的。
0赞 DDisciple 4/17/2019
@choroba 是的,我会抓住它,将其转换为 int 并执行 ++。
0赞 DDisciple 4/17/2019
@CharlesDuffy 实际上我不这么认为,但版本中总是有一个数字,没有其他数字,比如 version10 或 version_11 等。

答:

5赞 Anubis 4/17/2019 #1
updateVersion()
{
    [[ $1 =~ ([^0-9]*)([0-9]+) ]] || { echo 'invalid input'; exit; }     
    echo "${BASH_REMATCH[1]}$(( ${BASH_REMATCH[2]} + 1 ))"
}

# Usage
updateVersion version_11         # output: version_12
updateVersion version11          # output: version12
updateVersion something_else123  # output: something_else124
updateVersion "with spaces 99"   # output: with spaces 100

# Putting it in a variable
v2="$(updateVersion version2)"
echo "$v2"                       # output: version3

评论

0赞 DDisciple 4/17/2019
我选择了这个,因为它是最简单的一个。你们都是非常好的答案,我学到了很多东西,谢谢!
3赞 Charles Duffy 4/17/2019 #2
incrementTrailingNumber() {
  local prefix number
  if [[ $1 =~ ^(.*[^[:digit:]])([[:digit:]]+)$ ]]; then
    prefix=${BASH_REMATCH[1]}
    number=${BASH_REMATCH[2]}
    printf '%s%s\n' "$prefix" "$(( number + 1 ))"
  else
    printf '%s\n' "$1"
  fi
}

用法如下:

$ incrementTrailingNumber version_30
version_31
$ incrementTrailingNumber foo-2.15
foo-2.16
$ incrementTrailingNumber noNumberHereAtAll  # demonstrate noop case
noNumberHereAtAll
5赞 choroba 4/17/2019 #3

使用参数扩展:

#! /bin/bash
shopt -s extglob
for version in version_1 version_19 version_34.14 ; do
    echo $version
    v=${version##*[^0-9]}
    ((++v))
    echo ${version%%+([0-9])}$v
done

extglob表示“一个或多个数字”的构造需要。+([0-9])

3赞 Flic 6/21/2019 #4

这里的聚会迟到了,但接受的答案有问题。它适用于 OP 在结尾之前没有数字的情况,但我有一个这样的例子:

1.0.143

为此,正则表达式需要更宽松一些。我是这样做到的,保留了前导零:

#!/usr/bin/env bash

updateVersion()
{
  [[ ${1} =~ ^(.*[^0-9])?([0-9]+)$ ]]  && \
    [[ ${#BASH_REMATCH[1]} -gt 0 ]] && \
      printf "%s%0${#BASH_REMATCH[2]}d" "${BASH_REMATCH[1]}" "$((10#${BASH_REMATCH[2]} + 1 ))" || \
      printf "%0${#BASH_REMATCH[2]}d" "$((10#${BASH_REMATCH[2]} + 1))" || \
    printf "${1}"
}

# Usage
updateVersion 09          # output 10
updateVersion 1.0.450     # output 1.0.451
updateVersion version_01  # output version_02
updateVersion version12   # output version13
updateVersion version19   # output version20

笔记:

  1. 您只需要将第一个参数用双引号括起来。printf
  2. 如果要在命令行上使用它,请替换为内容, 而不是在函数中。${1}""
  3. 如果您愿意,可以将最后一个切换到基本。如果您只是打印到 或 ,请考虑在每个 的末尾添加换行符 ()。printfechostdoutstderr\nprintf
  4. 您可以将函数内容合并为一行,但更难阅读。最好将其与 at every if () 和 else () 分成行,如上所述。\&&||

函数的作用 - 逐行:

  • 测试传递的值以一个或多个数字结尾,可以选择以至少一个非数字为前缀。相应地分为两组(索引从 1 开始)。
  • 当以数字结尾时,测试有一个非数字前缀(即组 1 > 0 的长度)。
  • 当存在非数字时,打印组 1(字符串),后跟组 2(用零填充的整数以匹配原始字符串大小)。第 2 组以 10 为基数,并按 1 递增。转换很重要 - 默认情况下,前导零被解释为八进制。
  • 当只有数字时,如上所述递增,但只打印组 2。
  • 如果输入是其他任何内容,则返回提供的字符串。