GitHub是全球最大的程式碼託管平台,許多軟體資源都可以在該網站上取得。有些人如筆者就喜歡除了把程式原始碼上傳到GitHub外,也把已經編譯好的二進制檔案也一併上傳到GitHub替每個倉庫(Repository)所提供的「Release」區,這樣一來不想自行編譯原始碼的使用者就可以直接到「Release」區中找到對應平台已經編譯好的二進制檔案來直接下載使用。
以Flameshot這個開源的跨平台螢幕截圖軟體為例,其GitHub倉庫網址如下:
我們可以在其Release
區下,找到各個版本已經官方編譯好的函式庫和重新打包過的原始碼專案。如下圖:
其中,flameshot-12.1.0-1.ubuntu-22.04.amd64.deb
就是給Ubuntu的DEB安裝包,我們可以將其下載下來,就能在Ubuntu上安裝使用。
然而每次都要用網頁瀏覽器開啟GitHub來找到這個頁面來載最新版的檔案好像也挺麻煩的,在懶惰蟲的趨使下,就必須要想個方式能夠直接在Linux環境下,以指令的方式下載到GitHub倉庫上最新發佈出來的檔案。
GitHub提供的 /releases/latest
HTTP API
GitHub有提供許多方便的HTTP API,其中的/releases/latest
可以協助我們做到這件事。HTTP請求的網址格式如下:
GET https://api.github.com/repos/<user>/<repo>/releases/latest
以剛才提到的Flameshot為例,就是:
GET https://api.github.com/repos/flameshot-org/flameshot/releases/latest
這支API的回傳值大概如以下這樣(已刪減冗長訊息):
{
"url": "https://api.github.com/repos/flameshot-org/flameshot/releases/71146895",
"assets_url": "https://api.github.com/repos/flameshot-org/flameshot/releases/71146895/assets",
"upload_url": "https://uploads.github.com/repos/flameshot-org/flameshot/releases/71146895/assets{?name,label}",
"html_url": "https://github.com/flameshot-org/flameshot/releases/tag/v12.1.0",
"id": 71146895,
"author": {
"login": "borgmanJeremy",
"id": 46930769,
"node_id": "MDQ6VXNlcjQ2OTMwNzY5",
"avatar_url": "https://avatars.githubusercontent.com/u/46930769?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/borgmanJeremy",
"html_url": "https://github.com/borgmanJeremy",
"followers_url": "https://api.github.com/users/borgmanJeremy/followers",
"following_url": "https://api.github.com/users/borgmanJeremy/following{/other_user}",
"gists_url": "https://api.github.com/users/borgmanJeremy/gists{/gist_id}",
"starred_url": "https://api.github.com/users/borgmanJeremy/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/borgmanJeremy/subscriptions",
"organizations_url": "https://api.github.com/users/borgmanJeremy/orgs",
"repos_url": "https://api.github.com/users/borgmanJeremy/repos",
"events_url": "https://api.github.com/users/borgmanJeremy/events{/privacy}",
"received_events_url": "https://api.github.com/users/borgmanJeremy/received_events",
"type": "User",
"site_admin": false
},
"node_id": "RE_kwDOBWsOdM4EPZ2P",
"tag_name": "v12.1.0",
"target_commitish": "master",
"name": "v12.1.0",
"draft": false,
"prerelease": false,
"created_at": "2022-07-03T13:42:21Z",
"published_at": "2022-07-03T18:03:55Z",
"assets": [
{
"url": "https://api.github.com/repos/flameshot-org/flameshot/releases/assets/70446299",
"id": 70446299,
"node_id": "RA_kwDOBWsOdM4EMuzb",
"name": "flameshot-12.1.0-1-lp15.2.x86_64.rpm",
"label": null,
"uploader": {
"login": "borgmanJeremy",
"id": 46930769,
"node_id": "MDQ6VXNlcjQ2OTMwNzY5",
"avatar_url": "https://avatars.githubusercontent.com/u/46930769?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/borgmanJeremy",
"html_url": "https://github.com/borgmanJeremy",
"followers_url": "https://api.github.com/users/borgmanJeremy/followers",
"following_url": "https://api.github.com/users/borgmanJeremy/following{/other_user}",
"gists_url": "https://api.github.com/users/borgmanJeremy/gists{/gist_id}",
"starred_url": "https://api.github.com/users/borgmanJeremy/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/borgmanJeremy/subscriptions",
"organizations_url": "https://api.github.com/users/borgmanJeremy/orgs",
"repos_url": "https://api.github.com/users/borgmanJeremy/repos",
"events_url": "https://api.github.com/users/borgmanJeremy/events{/privacy}",
"received_events_url": "https://api.github.com/users/borgmanJeremy/received_events",
"type": "User",
"site_admin": false
},
"content_type": "application/x-rpm",
"state": "uploaded",
"size": 10698252,
"download_count": 33235,
"created_at": "2022-07-03T18:02:23Z",
"updated_at": "2022-07-03T18:02:25Z",
"browser_download_url": "https://github.com/flameshot-org/flameshot/releases/download/v12.1.0/flameshot-12.1.0-1-lp15.2.x86_64.rpm"
},
{
"url": "https://api.github.com/repos/flameshot-org/flameshot/releases/assets/70446300",
"id": 70446300,
"node_id": "RA_kwDOBWsOdM4EMuzc",
"name": "flameshot-12.1.0-1-lp15.2.x86_64.rpm.sha256sum",
"label": null,
"uploader": {
"login": "borgmanJeremy",
"id": 46930769,
"node_id": "MDQ6VXNlcjQ2OTMwNzY5",
"avatar_url": "https://avatars.githubusercontent.com/u/46930769?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/borgmanJeremy",
"html_url": "https://github.com/borgmanJeremy",
"followers_url": "https://api.github.com/users/borgmanJeremy/followers",
"following_url": "https://api.github.com/users/borgmanJeremy/following{/other_user}",
"gists_url": "https://api.github.com/users/borgmanJeremy/gists{/gist_id}",
"starred_url": "https://api.github.com/users/borgmanJeremy/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/borgmanJeremy/subscriptions",
"organizations_url": "https://api.github.com/users/borgmanJeremy/orgs",
"repos_url": "https://api.github.com/users/borgmanJeremy/repos",
"events_url": "https://api.github.com/users/borgmanJeremy/events{/privacy}",
"received_events_url": "https://api.github.com/users/borgmanJeremy/received_events",
"type": "User",
"site_admin": false
},
"content_type": "application/octet-stream",
"state": "uploaded",
"size": 147,
"download_count": 2173,
"created_at": "2022-07-03T18:02:25Z",
"updated_at": "2022-07-03T18:02:25Z",
"browser_download_url": "https://github.com/flameshot-org/flameshot/releases/download/v12.1.0/flameshot-12.1.0-1-lp15.2.x86_64.rpm.sha256sum"
}
],
"tarball_url": "https://api.github.com/repos/flameshot-org/flameshot/tarball/v12.1.0",
"zipball_url": "https://api.github.com/repos/flameshot-org/flameshot/zipball/v12.1.0"
}
其中,tarball_url
和zipball_url
欄位是GitHub替每個Release主動提供的快照下載網址,而assets
欄位是GitHub倉庫的擁有者自行在建立Release時所額外加入的檔案。assets
欄位中的每個檔案的browser_download_url
欄位,正是該檔案的下載網址。
curl
指令
我們可以利用Linux發行版中常會內建的curl
指令來調用GitHub提供的這支API。如果環境中沒有安裝curl
的話,基於Debian的Linux發行版可以使用以下指令來安裝:
紅帽系的Linux發行版則可以使用以下指令來安裝curl
:
curl
指令的使用方式如下:
curl -fsS https://api.github.com/repos/flameshot-org/flameshot/releases/latest
curl
指令的-f
參數可以讓curl
指令在遇到HTTP錯誤時不繼續取得主體(body);-s
參數可以讓curl
指令只輸出URL資源的主體(body)資料;-S
參數可以在使用-s
參數時依然輸出錯誤訊息到標準錯誤(stderr)中。
sed
指令
接著我們可以利用Linux作業系統中內建的sed
指令來處理curl
指令呼叫GitHub的API所回傳的JSON資料。
例如要抓取browser_download_url
欄位中的網址,sed
指令可以這樣寫:
sed -r -n 's/.*"browser_download_url": *"(.*)".*/\1/p'
sed
指令的-r
參數可以讓\1
發揮作用(也就是正規表示式的群組功能);-n
參數可以讓輸出結果只保留/p
要輸出的部份(此處就是\1
)。
結合curl
指令,寫法如下:
curl -fsS https://api.github.com/repos/flameshot-org/flameshot/releases/latest | sed -r -n 's/.*"browser_download_url": *"(.*)".*/\1/p'
如上圖,由於每個Release中可能會有超過一個的額外檔案,因此我們必須要確保這些網址所連結到的檔案資源都是我們需要下載,不然就得繼續再過濾。這部份可以再使用grep
指令來達成,或者我們也可以修改剛才寫好的sed
指令,在(.*)
內加入更嚴苛的條件,例如:
curl -fsS https://api.github.com/repos/flameshot-org/flameshot/releases/latest | sed -r -n 's/.*"browser_download_url": *"(.*\.ubuntu-22\.04\.amd64\.deb)".*/\1/p'
如上圖,只剩下一個網址了!
再次使用curl
指令
有了單獨的下載網址就很容易了,利用Shell的命令替換(Command Substitution)語法,將前面的curl
和sed
指令找出的網址變成參數傳給curl
指令使用,讓curl
去下載這個網址的資源。
結合後指令寫法如下:
curl -fL "$(curl -fsS https://api.github.com/repos/flameshot-org/flameshot/releases/latest | sed -r -n 's/.*"browser_download_url": *"(.*\.ubuntu-22\.04\.amd64\.deb)".*/\1/p')" -O
curl
指令的-L
參數可以讓curl
允許轉址;-O
參數可以將網址資源儲存成檔案,並自動取檔名。
如此一來就能用一行指令把GitHub倉庫上最新發佈的檔案給下載下來了!
如果我們不想讓curl
自動取檔名,可以將指令中的-O
參數替換成-o
參數,並接上檔案路徑,例如:
curl -fL "$(curl -fsS https://api.github.com/repos/flameshot-org/flameshot/releases/latest | sed -r -n 's/.*"browser_download_url": *"(.*\.ubuntu-22\.04\.amd64\.deb)".*/\1/p')" -o flameshot.deb