做爲一名有理想的程序員,咱們或多或少都會寫一些 shell
腳本,它們可能很短,只有簡單的幾個命令,也可能很是長,包含了系統檢查、編譯和運行等多個龐大複雜的任務java
在安裝軟件的時候,你必定見過不少名爲configure
的 shell
腳本,這個腳本能夠保證軟件不會破壞當前系統,而且擁有能夠正常安裝的環境配置,實現這個腳本須要不少的邏輯和技巧。做爲一名使用了多年 shell
腳本的老司機,我積累了大量關於 shell
腳本的使用技巧來提升腳本編寫效率,今天,我將其中的一些精華分享出來,但願能對一些人有所幫助linux
剛開始的時候,個人腳本就是一系列的命令,像流水帳同樣,通常用來節省寫多個標準 shell
語句的時間。好比發佈一個 web
網站,其中一個任務就是把靜態文件解壓到 nginx
目錄,腳本大概長這樣nginx
$ cp static_file.tar.gz /usr/nginx/home/
$ cd /usr/nginx/home/
$ tar -zxvf static_file.tar.gz
複製代碼
這個腳本固然節省了不少的時間,但從長遠來看,這並非一個頗有用的腳本。過了一段時間,我學會了一些其餘的方式來寫腳本,並用來完成更有挑戰性的任務,好比建立一個軟件包,安裝軟件或者備份一個文件服務器等程序員
就像其餘的變成語言同樣,條件判斷是一個易用且強大的語法。條件語句可讓咱們的程序按照必定的邏輯執行。個人每一個腳本幾乎都用到了條件語句web
最基本的條件語句使用 if
標記。if
語句能夠對一些條件進行判斷,咱們能夠根據判斷的結果來決定腳本的走向。例如,咱們能夠檢查 java bin
目錄是否存在,若是存在,就表明 java
已經正常安裝,而後咱們能夠利用腳本,將 java
的運行目錄放到 path
環境變量中,這樣咱們就能夠在任意一個文件目錄下運行 java
命令了shell
if [ -d "$JAVA_HOME/bin" ] ; then
PATH="$JAVA_HOME/bin;$PATH"
fi
複製代碼
if
條件判斷還有一些高級的用法,好比我想判斷一個目錄是否存在,不存在則建立bash
[ -d "$1" ] || mkdir --parent "$1"
複製代碼
也許咱們會想讓腳本只能由特定的用戶執行。儘管 linux
已經有了用戶和組的權限控制,但仍是想讓腳原本控制。好比可使用腳原本控制只能是當前 web
容器的全部者才能執行,或者只有 root
用戶才能執行。linux
系統給咱們提供了兩個環境變量去實現這個功能,其中一個是 $USER
,獲取當前用戶名。另外一個是 $UID
獲取當前用戶的惟一標記服務器
在一個多用戶,多應用的環境中,下面的示例展現瞭如何限制,只有 apple
這個用戶才能夠執行這個腳本。 if
語句能夠理解爲向用戶提問:"執行的用戶是否是 不是apple ?"。 若是發現執行人就是 apple
,第一個 echo
就會被執行,後邊緊跟着一個 exit 1
,意味着結束腳本執行app
if [ "$USER" != 'apple' ] ; then
echo "此腳本只能由 apple 執行"
exit 1
fi
echo "繼續執行腳本"
複製代碼
第二個例子展現了,只有 root
用戶才能執行此腳本。由於 UID
爲 0
的就是 root
用戶,咱們能夠在判斷時使用 -gt
擴展選項來禁止全部 UID
大於 0
的用戶繼續執行腳本學習
if [ "$UID" -gt 0 ] ; then
echo "此腳本只能由 root執行"
exit 1
fi
echo "繼續執行腳本"
複製代碼
和任何能夠執行的文件同樣,腳本文件也能夠接受參數。下邊會展現一些參數傳遞的例子。但必定要注意,要寫好代碼,不只要讓程序執行咱們想要執行的任務,也要保證程序不要執行咱們不想執行的任務。我通常在腳本中會確保在用戶沒有參數傳遞進來的時候不作任何事情。所以,我寫腳本的第一件事就是使用 $#
檢查腳本的參數是否傳遞
if [ $# -eq 0 ] ; then
echo "參數錯誤"
exit 1
fi
echo "得到了參數: $#"
複製代碼
能夠在命令行中傳遞多個參數給腳本, 腳本中對於用戶提供的變量提供了很簡單的獲取方式,以 $
符號開頭,按照參數遞增,例如 $1 $2 $3
等。 下邊的例子是打印用戶輸入的三個參數。固然,咱們還必需要注意根據參數傳遞的數量作不一樣的處理。
echo $1 $2 $3
複製代碼
看了上面的代碼,你也許會問:是否是跳過了 $0
?
嗯。。。是的,由於 $0
在腳本中也是一個很是有用的變量,他表明咱們執行的腳本的名稱
echo $0
複製代碼
對於這個參數的一個很是重要的應用就是在腳本中生成一個包含腳本名稱的日誌。最簡單的例子大概以下
echo test >> $0.log
複製代碼
上邊只是最簡單使用,通常在使用時須要加上一些邏輯判斷,好比判斷文件位置是否可寫等
另一個很是有用的功能就是在腳本執行的時候讓用戶輸入一些信息,以下
echo "請輸入一個字母: "
read word
echo $word
複製代碼
這樣就可讓用戶在執行腳本的時候進行判斷
read -p "是否安裝此軟件? [Y/n]: " answ
if [ "$answ" == ’n' ] ; then exit 1 fi echo "開始安裝軟件" 複製代碼
幾年以前,我寫了一個腳本去安裝最新版本的 jdk
,這個腳本的基本流程就是解壓 jdk
包到指定的目錄,更新 jdk
的軟鏈,而後使用一些其餘的方式讓系統識別這個新版本。這就須要考慮一個問題,若是我解壓 jdk
包失敗了,繼續執行腳本就會破壞我以前安裝的 jdk
環境。因此個人腳本必定要能解決這種問題,也就是說只有解壓成功才繼續執行腳本,大概的源碼以下
tar kxzmf jdk-8-linux-x64.tar.gz -C /home/apple/jdk --checkpoint=.500; ec=$?
if [$ec -ne 0 ] ; then
echo "安裝 jdk 失敗"
exit 1
fi
複製代碼
識別系統命令執行出錯最簡單的方法時使用 $?
變量,以下例
ls T; ec=$?; echo $ec
複製代碼
咱們若是先執行 touch T
而後執行上邊的腳本,ec
會是 0
。而後刪除 T
文件,調用 rm T
。再次執行腳本,ec
會變成 2
,由於 T
文件沒有找到,系統會拋出一個爲 2
的錯誤標記
在一些稍微複雜寫的場景,咱們可能就會想要用一些比較高級的語言實現,相似 Python
C
或者 Java
。其實很時候徹底沒有必要。shell
腳本很是強大,有不少值得學習和使用的東西。我但願經過上邊的簡單介紹能讓剛剛使用 shell
並準備放棄的人瞭解到 一點 shell
的強大及魅力