如何用自解壓腳本打包軟件和數據
譯文【51CTO.com快譯】有時,您需要一種快速可靠的方式向用戶分發數據或軟件,無需使用包管理器(比如說,最終用戶可能沒有安裝應用程序的root訪問權限)。
這個問題可以通過使用容器和Podman或Docker來解決,但如果它們在目標系統上沒有,怎么辦?如果要求之一是應用程序在裸機環境中正常工作,又怎么辦?
您可以將Python與pip一起使用(您可能知道也可以打包非Python工件),但是那樣可能面臨一些安裝上的限制(虛擬環境或--user選項),更不用說需要樣板代碼來打包Python代碼了。
我在本文中演示了一種非常小巧但有效的技術來編寫不需要提升權限的自解壓腳本。
設置您的數據
Damiaan Zwietering有一個很酷的關于新冠病毒的Git代碼存儲庫,帶有數據和可視化(Jupyter書籍和Excel電子表格),但沒有安裝程序。假設您想將其提供給自己的用戶,但他們無權訪問Git。您就可以為用戶創建自解壓安裝程序。
在實際情況下,您已經擁有想要分發的數據。但是您有一些示例數據要處理,首先將該存儲庫克隆到主目錄:
- $ git clone https://gitlab.com/dzwietering/corona.git
現在有很多數據和不那么淺的目錄結構,但是您可以使用git archive命令創建一個.tar文件:
- $ cd $HOME / corona
- $ git archive --verbose --output $tempdir/corona.tar.gz HEAD
對于本示例,該打包文件是您想要與用戶共享的文件。
自解壓腳本的結構
自解壓腳本分為以下幾個部分:
1. 幫助用戶提取數據的代碼(“有效載荷”)
2. 從腳本中分離數據(要提取)的錨點
3. 提取其后數據的錨點位置
事實證明,Bash非常擅長以這種方式來定義腳本。
創建有效載荷
這里有個想法:假設您需要分發的數據是一個含有許多腳本和數據的目錄。您希望保持權限和結構完好無缺,您希望用戶將其“解壓縮”到主目錄中。
這聽起來像是tar命令的工作。但是假設您的用戶不知道如何使用tar,或者他們在安裝tarball文件時想要特殊選項(比如僅提取特定文件)。
另一個問題是您的.tar存檔是一個二進制文件。如果您要通過電子郵件發送,必須使用Uuencode或Base64對其進行正確編碼,以便安全傳輸。
該怎么辦?不要扔掉.tar文件。相反,準備好它,以便您可以將其附加到Bash腳本(您將很快編寫):
- $ base64 $tempdir/corona.tar.gz > $tempdir/corona_payload
- $ file $tempdir/corona_payload
- /tmp/tmp.8QNdzdKEkG/corona_payload: ASCII text
從.tar文件提取數據
您可以將所有內容倒到新目錄中:
- $ newbase=$HOME/coronadata
- $ test ! -d $newbase && /bin/mkdir --parents --verbose $newbase
- $ tar --directory $newbase \
- --file corona.tar.gz --extract --gzip --verbose
也可以僅提取其中的一部分,比如措施、試驗和測試目錄。
- $ newbase=$HOME/coronadata
- $ test ! -d $newbase && /bin/mkdir --parents --verbose $newbase
- $ tar --directory $newbase --file corona.tar.gz \
- --extract --gzip --verbose measures experiment test
針對這次演練,將全部內容提取到基本目錄(比如$HOME),因此結果如下:
- $HOME/$COVIDUSERDIR
剖析自解壓腳本
以下是我的自解壓腳本的代碼。您可以將腳本保存在自己的Git存儲庫中,并重復用于其他部署環境。要注意的事項如下:
- SCRIPT_END是有效載荷在腳本里面開始的位置。
- 它凈化用戶輸入。
- 一旦您搞清楚了元數據的位置,從腳本中提取($0),重新解碼成二進制代碼,然后拆包。
- #!/usr/bin/env bash
- # Author: Jose Vicente Nunez
- SCRIPT_END=$(/bin/grep --max-count 2 --line-number ___END_OF_SHELL_SCRIPT___ "$0"| /bin/cut --field 1 --delimiter :| /bin/tail -1)|| exit 100
- ((SCRIPT_END+=1))
- basedir=
- while test -z "$basedir"; do
- read -r -p "Where do you want to extract the COVID-19 data, relative to $HOME? (example: mydata -> $HOME/mydata. Press CTRL-C to abort):" basedir
- done
- :<<DOC
- Sanitize the user input. This is quite restrictive, so it depends of the real application requirements.
- DOC
- CLEAN=${basedir//_/}
- CLEAN=${CLEAN// /_}
- CLEAN=${CLEAN//[^a-zA-Z0-9_]/}
- if [ ! -d "$HOME/$CLEAN" ]; then
- echo "[INFO]: Will try to create the directory $HOME/$CLEAN"
- if ! /bin/mkdir --parent --verbose "$HOME/$CLEAN"; then
- echo "[ERROR]: Failed to create $HOME/$CLEAN"
- exit 100
- fi
- fi
- /bin/tail --lines +"$SCRIPT_END" "$0"| /bin/base64 -d| /bin/tar --file - --extract --gzip --directory "$HOME/$CLEAN"
- exit 0
- # Here's the end of the script followed by the embedded file
- ___END_OF_SHELL_SCRIPT___
那么您如何將有效載荷添加到腳本?只要用一點cat粘合劑將兩部分組合起來:
- $ cat covid_extract.sh \
- $tempdir/corona_payload > covid_final_installer.sh
使它變成可執行:
- $ chmod u+x covid_final_installer.sh
您可以看到安裝程序如何與有效載荷結合起來。由于含有有效載荷,它很龐大。
運行安裝程序
這管用嗎?不妨親自試一下:
- $ ./covid_final_installer.sh
- Where do you want to extract the COVID-19 data, relative to /home/josevnz? (example: mydata -> /home/josevnz/mydata. Press CTRL-C to abort):COVIDDATA
- [INFO]: Will try to create the directory /home/josevnz/COVIDDATA
- /bin/mkdir: created directory '/home/josevnz/COVIDDATA'
- $ tree /home/josevnz/COVIDDATA
- /home/josevnz/COVIDDATA
- ├── acaps_covid19_government_measures_dataset_0.xlsx
- ├── acaps_covid19_government_measures_dataset.xlsx
- ├── COVID-19-geographic-disbtribution-worldwide.xlsx
- ├── EUCDC.ipynb
- ├── experiment
- ...
自解壓安裝程序很有用
我覺得自解壓安裝程序很有用,原因多多。
首先,您可以隨意將它們做成很復雜或很簡單。最復雜的部分在于規定腳本應從哪里提取有效載荷。
知道這種方法很實用,因為惡意軟件安裝程序也使用這種方法。現在您有了更充分的準備可以在腳本中發現這樣的代碼。同樣重要的是,現在您知道如何通過在自己的自解壓腳本中驗證用戶輸入來阻止外殼注入濫用現象。
原文標題:Package software and data with self-compressed scripts,作者:Jose Vicente Nunez
【51CTO譯稿,合作站點轉載請注明原文譯者和出處為51CTO.com】