【问题标题】:Extract version number from file in shell script从shell脚本中的文件中提取版本号
【发布时间】:2011-09-08 20:56:42
【问题描述】:

我正在尝试编写一个增加版本号的 bash 脚本

{major}.{minor}.{revision}

例如。

1.2.13

有没有一种好方法可以使用 sed 或 awk 之类的方法轻松提取这 3 个数字,这样我就可以增加 {revision} 数字并输出完整的版本号字符串。

【问题讨论】:

    标签: bash shell scripting sed


    【解决方案1】:
    $ 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 算术扩展递增:$((x+1))

    【讨论】:

      【解决方案2】:

      使用数组的纯 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[*]}"。谢谢,可以好好利用了!
      【解决方案3】:

      我更喜欢这种事情的“剪切”命令

      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"
      

      我知道这不是最短的方法,但对我来说它是最容易理解和阅读的......

      【讨论】:

      • 4 个子外壳、3 个管道、3 个完整的进程(至少)只是为了更改一两个字符!这有点过分了。
      • @fgm 但无论您是否使用 bash,至少它都有效。 +1您当然可以简化: echo "$(echo $version | cut -d.-f-2).$(expr $(echo $version | cut -d.-f3) + 1)" 它是仍然有很多子外壳和管道,但是除非您使用的是超微型功率不足的嵌入式设备,否则这无关紧要。如果您追求速度,那么 bash 一开始可能不是最佳选择;-)
      【解决方案4】:

      另一种 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
      

      【讨论】:

      • +1,非常易读的给猫剥皮的方法。你能解释一下为什么必须写 IFS=".$IFS" 而不是简单的 IFS=""。 ?我已经检查过 IFS="。"而且它不能正常工作。
      • 我的偏执狂,因为如果默认值也不存在 something 将无法工作:-) 我的猜测是,如果 IFS 不包含换行符(通过默认它有一个空格、一个制表符和一个换行符),然后读取无法正常工作。也就是说,我刚刚在这里尝试过,并且正在执行 IFS="。"在这里工作正常...(在 cygwin 下运行的 bash 3.2.51)。
      【解决方案5】:

      Awk 让它变得非常简单:

      echo "1.2.14" | awk -F \. {'print $1,$2, $3'} 将打印出 1 2 14。

      flag -F 指定分隔符。

      如果您希望保存其中一个值:

      firstVariable=$(echo "1.2.14" | awk -F \. {'print $1'})

      【讨论】:

      • 但是您必须为每个重复 echo | awk 三次。
      • 是的。我更喜欢 Cris J 的答案。
      • 谢谢!如果有人只需要major.minor,这应该给它:echo "1.2.14" | awk -F \. '{version=$1"."$2; print version}' 将打印出1.2
      【解决方案6】:

      我使用shell自带的分词;像

      oIFS="$IFS"
      IFS=.
      set -- $version
      IFS="$oIFS"
      

      尽管由于字母或日期后缀以及其他令人讨厌的不一致位,您通常需要小心使用版本号。之后,位置参数将设置为$version的组件:

      $1 = 1
      $2 = 2
      $3 = 13
      

      $IFS 是一组单个字符,而不是字符串,因此这不适用于多字符字段分隔符,尽管您可以使用 IFS=.-.- 上进行拆分。)

      【讨论】:

      • 我不确定这与我问的问题有什么关系,也许我误解了 $IFS 是什么以及 $version 的设置。
      • $IFS 是shell用来进行自己的字段(“单词”)拆分的东西;我正在保存原始值(空格、制表符、换行符)并将其设置为.,然后使用set 强制$version 进行分词。我将扩展答案。
      • mod +1:非常巧妙。 IFS 是 shell 使用的“输入字段分隔符”。它通常设置为制表符、空格、回车。 geekasaur 正在将其更改为期间。 set -- $version 将命令行参数替换为按句点分隔的 $version 字段。因此,这三个部分现在是$1$2$3。如果你不想使用 set,你可以试试这个:echo $version | read major minor revision。它没有那么紧凑,但不会弄乱您可能仍在使用的命令行参数。
      • @David:注意while 循环可能在子shell 中运行,可能会产生令人惊讶的结果(例如,循环中的变量设置不会被脚本的其余部分看到)。 stackoverflow.com/questions/6245246/…
      • 伙计,你很快。我在我的 cmets 中看到了 while 行并将其删除。我没有超过一分钟。管道输入到 while 读取循环的旧习惯。实际上,我放的东西在 BASH 中不起作用,但在我使用的 Kornshell 中起作用。它与 BASH 完全兼容,除非它不是。为了让它在 bash 中工作,您必须将 $version 作为此处的文档。
      【解决方案7】:

      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
      

      【讨论】:

        【解决方案8】:

        使用内置read 命令将字符串拆分为数组的fgm 解决方案的小变化。请注意,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"
        

        见:How do I split a string on a delimiter in Bash?

        【讨论】:

          猜你喜欢
          • 2020-03-08
          • 2021-01-25
          • 2015-08-16
          • 1970-01-01
          • 1970-01-01
          • 2012-10-16
          • 2018-09-25
          • 1970-01-01
          • 2022-11-14
          相关资源
          最近更新 更多