LoginSignup
7
2

More than 1 year has passed since last update.

文字列からバージョン情報だけを抜き出す正規表現(bash/dash/ash/zsh で grep)

Last updated at Posted at 2020-10-04

文字列「v2.1.0-39-g4e1ede1」から "2.1.0" もしくは "v2.1.0" のみ・・を抜き出したい。

可能ならメジャー、マイナー、パッチのバージョンも個別に。プレリリースやビルドはいらない。そして bash zsh などでも使えるように POSIX 互換で。

... ... って grep だっけ? sed だっけ?もしかして awk

確かに セマンティック・バージョニング 2.0.0 に完全に準拠している構文であれば、公式の正規表現を利用できます。

^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$

SemVer文字列をチェックするために推奨される正規表現(RegEx)はありますか? | FAQ @ semver.org より)
オンラインで動作を見る @ paiza.IO

しかし、これは「構文チェック用の正規表現」であるため、準拠していない 1.1 などはエラーになります。パッチのバージョンが抜けているからです。

つまり、バージョンを抜き出すシンプルな用途には向いていません。普通に文字列から X.Y.Z もしくは vX.Y.Z を抜き出したいだけなのに。

意外なことに「bash 正規表現 バージョン情報 抜き出す」でググってみても、文字列からバージョン番号を抜き出すだけ・・の記事がなかったので自分のググラビリティとして。

TL; DR (今北産業)

grep-o オプションで正規表現にマッチした文字のみ抜き出し、-E オプションで細かい指定をし、| head で最初にマッチしたもののみに絞る。

grep -o -E "([0-9]+\.){1}[0-9]+(\.[0-9]+)?" | head -n1
例(vなし)
$ echo "v2.1.0-39-g4e1ede1" | grep -o -E "([0-9]+\.){1}[0-9]+(\.[0-9]+)?" | head -n1
2.1.0
例(vつき)
$ echo "v2.1.0-39-engine-1.2.3" | grep -o -E "(v[0-9]+\.){1}[0-9]+(\.[0-9]+)?" | head -n1
v2.1.0
応用(メジャー、マイナー、パッチバージョンを抜き出す)
$ MyVersion=$(echo "v2.1.0-39-engine-1.2.3" | grep -o -E "([0-9]+\.){1}[0-9]+(\.[0-9]+)?" | head -n1)
$ echo $MyVersion | awk -F. '{printf "Major:%d, Minor:%d, Patch:%d\n", $1,$2,$3}'
Major:2, Minor:1, Patch:0

TS; DR

sample.sh(色々なパターンをテスト)
#!/bin/bash

test() {
    input="$1"
    expect="$2"

    actual=$(echo "${input}" | grep -o -E "([0-9]+\.){1}[0-9]+(\.[0-9]+)?" | head -n1)

    [ "$expect" = "$actual" ] && {
        printf '%s' '[OK] '
    } || {
        printf '%s' '[ng] '
    }

    printf "Input: %s\t-> Output: %s\n" "$input" "$actual"
}

#    Input        Expect
test "2"          ""
test ".2"         ""
test "..2"        ""
test "2.1"        "2.1"
test "2..1"       ""
test "version2"   ""
test "version2.1" "2.1"
test "22.11"      "22.11"
test "2.1.0"      "2.1.0"
test "2.1.10"     "2.1.10"
test "2.10.0"     "2.10.0"
test "22.1.0"     "22.1.0"
test "33.22.11"   "33.22.11"

test "v1.2-3.4.5.6.7"     "1.2"
test "v1.2.3.4.5.6.7.8"   "1.2.3"
test "v1.2.3-4.5.6-7"     "1.2.3"
test "2.1.0-39-g4e1ede"   "2.1.0"
test "v2.1.0-39-g4e1ede1" "2.1.0"

grep --version | head -n1

テスト結果
$ ./sample.sh
[OK] Input: 2    -> Output: 
[OK] Input: .2  -> Output: 
[OK] Input: ..2 -> Output: 
[OK] Input: 2.1 -> Output: 2.1
[OK] Input: 2..1        -> Output: 
[OK] Input: version2    -> Output: 
[OK] Input: version2.1  -> Output: 2.1
[OK] Input: 22.11       -> Output: 22.11
[OK] Input: 2.1.0       -> Output: 2.1.0
[OK] Input: 2.1.10      -> Output: 2.1.10
[OK] Input: 2.10.0      -> Output: 2.10.0
[OK] Input: 22.1.0      -> Output: 22.1.0
[OK] Input: 33.22.11    -> Output: 33.22.11
[OK] Input: v1.2-3.4.5.6.7      -> Output: 1.2
[OK] Input: v1.2.3.4.5.6.7.8    -> Output: 1.2.3
[OK] Input: v1.2.3-4.5.6-7      -> Output: 1.2.3
[OK] Input: 2.1.0-39-g4e1ede    -> Output: 2.1.0
[OK] Input: v2.1.0-39-g4e1ede1  -> Output: 2.1.0
grep (GNU grep) 3.4

上記のパターンに加えたいものがあれば遠慮なく編集リクくださーい。また、検知して欲しいパターンの抜けがあれば、遠慮なくコメントくださーい。

応用技 (メジャー、マイナー、パッチバージョンを抜き出す)

xx.yy.zzセマンティック・バージョニングなら awk で抜き出せます。

awk -F. '{printf "Major:%d, Minor:%d, Patch:%d\n", $1,$2,$3}'

Golangのメジャー、マイナー、パッチバージョンを抜き出す例
$ go version
go version go1.16.3 linux/amd64

$ GoVersion=$(go version | grep -o -E "([0-9]+\.){1}[0-9]+(\.[0-9]+)?" | head -n1)
$ echo $GoVersion | awk -F. '{printf "Major:%d, Minor:%d, Patch:%d\n", $1,$2,$3}'
Major:1, Minor:16, Patch:3

参考文献/あわせて読みたい

  • どのUNIXコマンドでも使える正規表現 @ Qiita
    • たった3つの正規表現メタ文字セットだけ知ればいい
      抜本的に正規表現を理解出来る、目から鱗の Qiita 記事です。Docker の Alpine でゴニョゴニョすることが多い人は POSIX 原理主義者になった方が良いと思いました。
7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2