{"id":17629855,"url":"https://github.com/ariel-rodriguez/sh-semversion-2","last_synced_at":"2025-07-30T03:32:57.573Z","repository":{"id":43859971,"uuid":"315332502","full_name":"Ariel-Rodriguez/sh-semversion-2","owner":"Ariel-Rodriguez","description":"POSIX tool for semversion","archived":false,"fork":false,"pushed_at":"2023-02-08T00:01:59.000Z","size":40,"stargazers_count":55,"open_issues_count":1,"forks_count":10,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-02T11:17:58.470Z","etag":null,"topics":["bourne-shell","compare","compare-versions","npm-version","npx","npx-version","posix","semversion","sh","versioning"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Ariel-Rodriguez.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2020-11-23T13:59:09.000Z","updated_at":"2025-05-09T17:18:36.000Z","dependencies_parsed_at":"2023-10-20T17:34:07.778Z","dependency_job_id":null,"html_url":"https://github.com/Ariel-Rodriguez/sh-semversion-2","commit_stats":{"total_commits":23,"total_committers":3,"mean_commits":7.666666666666667,"dds":0.08695652173913049,"last_synced_commit":"afbcaa37f85cd944db9b29e41549d95e4322dc10"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/Ariel-Rodriguez/sh-semversion-2","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ariel-Rodriguez%2Fsh-semversion-2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ariel-Rodriguez%2Fsh-semversion-2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ariel-Rodriguez%2Fsh-semversion-2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ariel-Rodriguez%2Fsh-semversion-2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Ariel-Rodriguez","download_url":"https://codeload.github.com/Ariel-Rodriguez/sh-semversion-2/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ariel-Rodriguez%2Fsh-semversion-2/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267803984,"owners_count":24146527,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-30T02:00:09.044Z","response_time":70,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bourne-shell","compare","compare-versions","npm-version","npx","npx-version","posix","semversion","sh","versioning"],"created_at":"2024-10-23T00:49:00.797Z","updated_at":"2025-07-30T03:32:57.539Z","avatar_url":"https://github.com/Ariel-Rodriguez.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# sh-semversion-2\n\n[![checks](https://github.com/Ariel-Rodriguez/sh-semversion-2/actions/workflows/github-ci.yml/badge.svg?branch=main)](https://github.com/Ariel-Rodriguez/sh-semversion-2/actions/workflows/github-ci.yml)\n\nSH script to compare versions using semversion 2.0 spec.\n\n- highly-cross-compatible shell compliant with the POSIX standard.\n\n- Semversion 2.0 compliant: https://semver.org/\n\n#\n\n| Method   | Command                                                                                                |\n| :------- | :----------------------------------------------------------------------------------------------------- |\n| **npx**  | `npx --no-install git+https://github.com/Ariel-Rodriguez/sh-semversion-2.git 1.0.0 2.0.0`              |\n| **curl** | `curl https://raw.githubusercontent.com/Ariel-Rodriguez/sh-semversion-2/main/semver2.sh -o semver2.sh` |\n| **wget** | `wget https://raw.githubusercontent.com/Ariel-Rodriguez/sh-semversion-2/main/semver2.sh`               |\n\n###\n\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eParam 1\u003c/th\u003e\n\u003cth\u003eParam 2\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e1.0.0\u003c/td\u003e\n\u003ctd\u003e0.1.0\u003c/td\u003e\n\u003ctd\u003e1\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e1.0.0-alpha\u003c/td\u003e\n\u003ctd\u003e1.0.0+metadata.build.1\u003c/td\u003e\n\u003ctd\u003e-1\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e1.0.0+metadata.build.1\u003c/td\u003e\n\u003ctd\u003e1.0.0+metadata.build.2\u003c/td\u003e\n\u003ctd\u003e0\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n- When A greater than B: returns 1\n- When A equals than B: returns 0\n- When A lower than B:returns -1\n\n# Usage\n\n```sh\nnpx sh-semversion-2 1.0.0-rc.0.a+metadata v1.0.0-rc.0+metadata\n# output 1\n```\n\n```sh\n./semver2.sh 1.0.0-rc.0.a+metadata v1.0.0-rc.0+metadata\n# output  1\n```\n\n## Tests\n\n```sh\n./test.sh print-only-failures\n# abort on first failure match\n./test.sh print-only-failures early-exit=true\n```\n\n```sh\n# semver2.0 happy path tests ordered by precedence\n# spec 11.4\ntests=(\n  1.0.0-0--1\n  1.0.0-0-0\n  1.0.0-0-0.alpha\n  1.0.0-0-1\n  1.0.0-alpha\n  1.0.0-alpha.1\n  1.0.0-alpha.beta\n  1.0.0-beta\n  1.0.0-beta.2\n  1.0.0-beta.11\n  1.0.0-rc.1\n  1.0.0+metadata.0.0.0\n  2.0.0-ALPHA\n  2.0.0-alpha\n)\n```\n\n```sh\nOK 1.0.0-alpha = 1.0.0-alpha\nOK 1.0.0-alpha \u003c 1.0.0-alpha.1\nOK 1.0.0-alpha \u003c 1.0.0-alpha.beta\nOK 1.0.0-alpha \u003c 1.0.0-beta\nOK 1.0.0-alpha \u003c 1.0.0-beta.2\nOK 1.0.0-alpha \u003c 1.0.0-beta.11\nOK 1.0.0-alpha \u003c 1.0.0-rc.1\nOK 1.0.0-alpha \u003c 1.0.0+metadata.0.0.0\nOK 1.0.0-alpha \u003c 2.0.0-ALPHA\nOK 1.0.0-alpha \u003c 2.0.0-alpha\nOK 1.0.0-alpha.1 \u003e 1.0.0-alpha\nOK 1.0.0-alpha.1 = 1.0.0-alpha.1\nOK 1.0.0-alpha.1 \u003c 1.0.0-alpha.beta\nOK 1.0.0-alpha.1 \u003c 1.0.0-beta\nOK 1.0.0-alpha.1 \u003c 1.0.0-beta.2\nOK 1.0.0-alpha.1 \u003c 1.0.0-beta.11\nOK 1.0.0-alpha.1 \u003c 1.0.0-rc.1\nOK 1.0.0-alpha.1 \u003c 1.0.0+metadata.0.0.0\nOK 1.0.0-alpha.1 \u003c 2.0.0-ALPHA\nOK 1.0.0-alpha.1 \u003c 2.0.0-alpha\nOK 1.0.0-alpha.beta \u003e 1.0.0-alpha\nOK 1.0.0-alpha.beta \u003e 1.0.0-alpha.1\nOK 1.0.0-alpha.beta = 1.0.0-alpha.beta\nOK 1.0.0-alpha.beta \u003c 1.0.0-beta\nOK 1.0.0-alpha.beta \u003c 1.0.0-beta.2\nOK 1.0.0-alpha.beta \u003c 1.0.0-beta.11\nOK 1.0.0-alpha.beta \u003c 1.0.0-rc.1\nOK 1.0.0-alpha.beta \u003c 1.0.0+metadata.0.0.0\nOK 1.0.0-alpha.beta \u003c 2.0.0-ALPHA\nOK 1.0.0-alpha.beta \u003c 2.0.0-alpha\nOK 1.0.0-beta \u003e 1.0.0-alpha\nOK 1.0.0-beta \u003e 1.0.0-alpha.1\nOK 1.0.0-beta \u003e 1.0.0-alpha.beta\nOK 1.0.0-beta = 1.0.0-beta\nOK 1.0.0-beta \u003c 1.0.0-beta.2\nOK 1.0.0-beta \u003c 1.0.0-beta.11\nOK 1.0.0-beta \u003c 1.0.0-rc.1\nOK 1.0.0-beta \u003c 1.0.0+metadata.0.0.0\nOK 1.0.0-beta \u003c 2.0.0-ALPHA\nOK 1.0.0-beta \u003c 2.0.0-alpha\nOK 1.0.0-beta.2 \u003e 1.0.0-alpha\nOK 1.0.0-beta.2 \u003e 1.0.0-alpha.1\nOK 1.0.0-beta.2 \u003e 1.0.0-alpha.beta\nOK 1.0.0-beta.2 \u003e 1.0.0-beta\nOK 1.0.0-beta.2 = 1.0.0-beta.2\nOK 1.0.0-beta.2 \u003c 1.0.0-beta.11\nOK 1.0.0-beta.2 \u003c 1.0.0-rc.1\nOK 1.0.0-beta.2 \u003c 1.0.0+metadata.0.0.0\nOK 1.0.0-beta.2 \u003c 2.0.0-ALPHA\nOK 1.0.0-beta.2 \u003c 2.0.0-alpha\nOK 1.0.0-beta.11 \u003e 1.0.0-alpha\nOK 1.0.0-beta.11 \u003e 1.0.0-alpha.1\nOK 1.0.0-beta.11 \u003e 1.0.0-alpha.beta\nOK 1.0.0-beta.11 \u003e 1.0.0-beta\nOK 1.0.0-beta.11 \u003e 1.0.0-beta.2\nOK 1.0.0-beta.11 = 1.0.0-beta.11\nOK 1.0.0-beta.11 \u003c 1.0.0-rc.1\nOK 1.0.0-beta.11 \u003c 1.0.0+metadata.0.0.0\nOK 1.0.0-beta.11 \u003c 2.0.0-ALPHA\nOK 1.0.0-beta.11 \u003c 2.0.0-alpha\nOK 1.0.0-rc.1 \u003e 1.0.0-alpha\nOK 1.0.0-rc.1 \u003e 1.0.0-alpha.1\nOK 1.0.0-rc.1 \u003e 1.0.0-alpha.beta\nOK 1.0.0-rc.1 \u003e 1.0.0-beta\nOK 1.0.0-rc.1 \u003e 1.0.0-beta.2\nOK 1.0.0-rc.1 \u003e 1.0.0-beta.11\nOK 1.0.0-rc.1 = 1.0.0-rc.1\nOK 1.0.0-rc.1 \u003c 1.0.0+metadata.0.0.0\nOK 1.0.0-rc.1 \u003c 2.0.0-ALPHA\nOK 1.0.0-rc.1 \u003c 2.0.0-alpha\nOK 1.0.0+metadata.0.0.0 \u003e 1.0.0-alpha\nOK 1.0.0+metadata.0.0.0 \u003e 1.0.0-alpha.1\nOK 1.0.0+metadata.0.0.0 \u003e 1.0.0-alpha.beta\nOK 1.0.0+metadata.0.0.0 \u003e 1.0.0-beta\nOK 1.0.0+metadata.0.0.0 \u003e 1.0.0-beta.2\nOK 1.0.0+metadata.0.0.0 \u003e 1.0.0-beta.11\nOK 1.0.0+metadata.0.0.0 \u003e 1.0.0-rc.1\nOK 1.0.0+metadata.0.0.0 = 1.0.0+metadata.0.0.0\nOK 1.0.0+metadata.0.0.0 \u003c 2.0.0-ALPHA\nOK 1.0.0+metadata.0.0.0 \u003c 2.0.0-alpha\nOK 2.0.0-ALPHA \u003e 1.0.0-alpha\nOK 2.0.0-ALPHA \u003e 1.0.0-alpha.1\nOK 2.0.0-ALPHA \u003e 1.0.0-alpha.beta\nOK 2.0.0-ALPHA \u003e 1.0.0-beta\nOK 2.0.0-ALPHA \u003e 1.0.0-beta.2\nOK 2.0.0-ALPHA \u003e 1.0.0-beta.11\nOK 2.0.0-ALPHA \u003e 1.0.0-rc.1\nOK 2.0.0-ALPHA \u003e 1.0.0+metadata.0.0.0\nOK 2.0.0-ALPHA = 2.0.0-ALPHA\nOK 2.0.0-ALPHA \u003c 2.0.0-alpha\nOK 2.0.0-alpha \u003e 1.0.0-alpha\nOK 2.0.0-alpha \u003e 1.0.0-alpha.1\nOK 2.0.0-alpha \u003e 1.0.0-alpha.beta\nOK 2.0.0-alpha \u003e 1.0.0-beta\nOK 2.0.0-alpha \u003e 1.0.0-beta.2\nOK 2.0.0-alpha \u003e 1.0.0-beta.11\nOK 2.0.0-alpha \u003e 1.0.0-rc.1\nOK 2.0.0-alpha \u003e 1.0.0+metadata.0.0.0\nOK 2.0.0-alpha \u003e 2.0.0-ALPHA\nOK 2.0.0-alpha = 2.0.0-alpha\n```\n\n# development\n\n## How to debug\n\n- Enable [DEBUG] messages\n\n```sh\n./semver2.sh v0.0.1 v0.0.1-rc debug\nDEBUG: Detected: 0 0 1 identifiers:\nDEBUG: Detected: 0 0 1 identifiers: rc\nDEBUG: MAJOR are equal\nDEBUG: MINOR are equal\nDEBUG: PATCH are equal\nDEBUG: Because releases without pre-release identifiers have higher precedence\n1\n```\n\n- Enable verbose\n\n```sh\n./semver2.sh v0.0.1 v0.0.1-rc debug verbose\n+ printf %s v0.0.1\n+ cut -d+ -f 1\n+ version_a=v0.0.1\n+ removeLeadingV v0.0.1\n+ printf %s0.0.1\n+ version_a=0.0.1\n+ printf %s v0.0.1-rc\n+ cut -d+ -f 1\n+ version_b=v0.0.1-rc\n+ removeLeadingV v0.0.1-rc\n+ printf %s0.0.1-rc\n+ version_b=0.0.1-rc\n+ printf %s 0.0.1\n+ cut -d. -f 1\n+ a_major=0\n+ printf %s 0.0.1\n+ cut -d. -f 2\n+ a_minor=0\n+ printf %s 0.0.1\n+ + cut -d- -f 1\ncut -d. -f 3\n+ a_patch=1\n+ a_pre=\n+ includesString 0.0.1 -\n+ string=0.0.1\n+ substring=-\n+ [ 0.0.1 != 0.0.1 ]\n+ printf 0\n+ return 0\n+ [ 0 = 1 ]\n+ printf %s 0.0.1-rc\n+ cut -d. -f 1\n+ b_major=0\n+ printf %s 0.0.1-rc\n+ cut -d. -f 2\n+ b_minor=0\n+ printf %s 0.0.1-rc\n+ cut -d. -f 3\n+ cut -d- -f 1\n+ b_patch=1\n+ b_pre=\n+ includesString 0.0.1-rc -\n+ string=0.0.1-rc\n+ substring=-\n+ [ rc != 0.0.1-rc ]\n+ printf 1\n+ return 1\n+ [ 1 = 1 ]\n+ printf %s 0.0.1-rc\n+ cut -d- -f 2\n+ b_pre=rc\n+ unit_types=MAJOR MINOR PATCH\n+ a_normalized=0 0 1\n+ b_normalized=0 0 1\n+ debug Detected: 0 0 1 identifiers:\n+ [ debug = debug ]\n+ printf DEBUG: %sDetected: 0 0 1 identifiers:  \\n\n+ debug Detected: 0 0 1 identifiers: rc\n+ [ debug = debug ]\n+ printf DEBUG: %sDetected: 0 0 1 identifiers: rc \\n\n+ cursor=1\n+ [ 1 -lt 4 ]\n+ printf %s 0 0 1\n+ cut -d  -f 1\n+ a=0\n+ printf %s 0 0 1\n+ cut -d  -f 1\n+ b=0\n+ [ 0 != 0 ]\n+ printf %s MAJOR MINOR PATCH\n+ cut -d  -f 1\n+ debug MAJOR are equal\n+ [ debug = debug ]\n+ printf DEBUG: %sMAJOR are equal \\n\n+ cursor=2\n+ [ 2 -lt 4 ]\n+ printf %s 0 0 1\n+ cut -d  -f 2\n+ a=0\n+ printf %s 0 0 1\n+ cut -d  -f 2\n+ b=0\n+ [ 0 != 0 ]\n+ printf %s MAJOR MINOR PATCH\n+ cut -d  -f 2\n+ debug MINOR are equal\n+ [ debug = debug ]\n+ printf DEBUG: %sMINOR are equal \\n\n+ cursor=3\n+ [ 3 -lt 4 ]\n+ printf %s 0 0 1\n+ cut -d  -f 3\n+ a=1\n+ printf %s 0 0 1\n+ cut -d  -f 3\n+ b=1\n+ [ 1 != 1 ]\n+ printf %s MAJOR MINOR PATCH\n+ cut -d  -f 3\n+ debug PATCH are equal\n+ [ debug = debug ]\n+ printf DEBUG: %sPATCH are equal \\n\n+ cursor=4\n+ [ 4 -lt 4 ]\n+ [ -z  ]\n+ [ -z rc ]\n+ [ -z  ]\n+ debug Because releases without pre-release identifiers have higher precedence\n+ [ debug = debug ]\n+ printf DEBUG: %sBecause releases without pre-release identifiers have higher precedence \\n\n+ outcome 1\n+ result=1\n+ printf %s1\\n\n+ return\nDEBUG: Detected: 0 0 1 identifiers:\nDEBUG: Detected: 0 0 1 identifiers: rc\nDEBUG: MAJOR are equal\nDEBUG: MINOR are equal\nDEBUG: PATCH are equal\nDEBUG: Because releases without pre-release identifiers have higher precedence\n1\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fariel-rodriguez%2Fsh-semversion-2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fariel-rodriguez%2Fsh-semversion-2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fariel-rodriguez%2Fsh-semversion-2/lists"}