プログラムdeタマゴ

nodamushiの著作物は、文章、画像、プログラムにかかわらず全てUnlicenseです

Shell(Bash,Power Shell)でバージョンソート

x.y.z形式のバージョンをソート

 バージョンの形式は、「接頭辞x.y.z」とする。これのソートは割と簡単。(接頭辞はvとかver.とか)

 

Shell(Bash)

※最初のVERSIONは、各行にversion情報がある情報を、パイプに流すコマンドなど

VERSION   | sed 's/^接頭辞//' | sort -n -t . -k 1,1 -k 2,2 -k 3,3 | sed 's/^/接頭辞/'

 sedで一度接頭辞を削除した後、「.」で文字を区切って数値としてsortし、最後に接頭辞をsedで再度付加する。

Power Shell

※最初のVERSIONは、各行にversion情報がある情報を、パイプに流すコマンドなど

VERSION |  sort {[Version]$_.Replace('接頭辞','')} 

 接頭辞を削除した文字列をSystem.Versionとしてソート。PowerShellの方が簡単だと…

 

x.y.z-αをソートしたい

 「接頭辞x.y.z」で済めば良いのだが、v0.1.2を複数作りたい(alpha版やらbeta版やら)とかなると面倒。しかも、-αの部分はあったりなかったりすることもよくある。

 ここでは、何もなし「接頭辞x.y.z」、日付「接頭辞x.y.z-YYYYMMDD」、ベータ版「接頭辞x.y.z-b0」、アルファ版「接頭辞x.y.z-a0」の順に並べる。

 

Shell(Bash)

上手い方法は思いつかなかったので、もうAWKでa,b,日付をゴリゴリと数値に変換した。

※最初のVERSIONは、各行にversion情報がある情報を、パイプに流すコマンドなど

VERSION | \
gawk 'match($0, /([0-9]+)\.([0-9]+)\.([0-9]+)(-([ab])?([0-9]+))?/, v){
  if(v[4]==""){v[5] = 0;v[6]=0;}
  else if(v[5]==""){v[5] = 1;}
  else if(v[5]=="b"){v[5] = 2;}
  else if(v[5]=="a"){v[5] = 3;}
  printf "%3s%3s%3s%s%8s@%s\n",v[1],v[2],v[3],v[5],v[6],$0;}' |\
sort  | sed 's/^.*@//'

 AWKで無理矢理-αの部分を数値の形式に変換している。格好いい事なんてせずに、もうベタベタの変換だ。

 -α部分が何もなければ「0.0」に、日付なら「1.日付」に、ベータ、アルファならそれぞれ2,3の番号を振った。RCやら色々増やすなら、if文を追加すれば良いでしょう。

 最後にprintfで成形して出力する。%3sなんかの文字列長は好きな様にすれば良いんじゃないかな。お好みなら%03dでもいいね。適当な区切り文字(@)で$0も保存して、後で取り出せるようにもしてある。(文字数カウントしても良いけど、面倒くさいし)

 後は、sortで並び替えて、sedで@以降を取り出す。

 

PowerShell

 やっぱゴリった。誰か上手い方法を教えて。

※VERSIONは、各行にversion情報がある情報を、パイプに流すコマンドなど

$version_regex=[regex]"(\d+\.\d+\.\d+)(-([ab])?(\d+))?"
function Get-VersionKey($x){
    If($x -match $version_regex){
        $s = $Matches[1]
        If(!$Matches[2]){
            $s = $s+"0.0"
        }ElseIf(!$Matches[3]){
            $s = $s+"1." +$Matches[4].PadLeft(8,"0")
        }ElseIf($Matches[3] -eq "a"){
            $s = $s + "3."+$Matches[4].PadLeft(8,"0")
        }ElseIf($Matches[3] -eq "b"){
            $s = $s + "2."+$Matches[4].PadLeft(8,"0")
        }
        return [Version]$s
    }
}

VERSION | sort { Get-VersionKey($_) }

 やり方はさっきとBashとほぼ一緒。一度"x.y.zα.n"という形に変換した後(日付のYYYYMMDDが8文字なので、PadLeftで全て8文字にしてある。変換される型はint32なので、ギリギリ入る。)、System.Versionに変換、それを元にソートする。

 

参考

PowerShell実践ガイドブック ~クロスプラットフォーム対応の次世代シェルを徹底解説~

PowerShell実践ガイドブック ~クロスプラットフォーム対応の次世代シェルを徹底解説~

「シェル芸」に効く!AWK処方箋

「シェル芸」に効く!AWK処方箋