前言
寫下這篇文章,是對自己在學習和使用過程中的總結,文筆不是很好,如果有什麼問題歡迎溝通交流
GitBook地址:https://hi-dhl.gitbooks.io/10-shell/content/
Shell是什麼
Shell是指一種應用程式,這個應用程式提供了一個介面,使用者通過這個介面訪問作業系統核心的服務, Shell指令碼(shell script),是一種為Shell編寫的指令碼程式。我們經常說的shell通常都是指shell指令碼。
環境和工具
Shell跟java、php、Python程式設計一樣,只要有一個能編寫程式碼的文字編輯器和一個能解釋執行的指令碼直譯器就可以了。
Mac OS,Linux 自帶了shell直譯器,Windows比較麻煩,因為Win7專業版和旗艦版預設安裝PowerShell,標準版和家庭版中就沒有安裝的,為了方便建議安裝cygwin
PHP、Python 也可以作為Shell程式設計
PHP、Python是屬於高階程式語言,但是也可以做Shell程式設計,因為只要有直譯器,也可以用作指令碼程式設計
如下是一個Python Shell Script示例(假設檔名叫op_python_base.py):
#!/usr/bin/env python3 //告訴Python從系統環境中找python
# -*- coding: utf-8 -*- //設定為UTF-8編碼
for index in range(10):
print(index);
複製程式碼
原始碼:op_python_base
如下是一個PHP Shell Script示例(假設檔名叫op_php_base.php):
#!/usr/bin/php
<?php
for($i=0 ;$i<10; $i++){
echo $i;
}
?>
複製程式碼
原始碼:op_php_base
為什麼要學習Shell
既然PHP、Python都可以用來寫指令碼程式設計,那為什麼還要學習陌生、晦澀難懂的Shell,主要有一下幾個原因
-
環境相容性,Win7專業版和旗艦版預設安裝PowerShell,標準版和家庭版中就沒有安裝的,其他主流的作業系統都預製了Shell直譯器,所以使用sh、bash編寫,提供給其他人使用是非常方便的,但是PHP、Python 等等需要安裝相應的環境
-
如果你想做一些定時任務比如說檢測程式是否存在,自動備份,或者說自動部署環境、伺服器之間的資料同步等等sh、bash會是你最好的選擇
sh與bash
sh: Bourne shell,POSIX(Portable Operating System Interface)標準的shell直譯器,它的二進位制檔案路徑通常是/bin/sh
bash: Bash是Bourne shell的替代品,屬GNU Project,二進位制檔案路徑通常是/bin/bash
第一個shell指令碼
我們先來看一個例子
我相信寫過程式碼的童鞋,應該對下面的程式碼很熟悉並不陌生,(假設檔名叫op_base.sh):
#!/usr/bin/env bash
mkdir code
cd code
for ((i=0; i<3; i++)); do
touch test_${i}.txt
echo "shell很簡單" >> test_${i}.txt
done
複製程式碼
第一行:從系統path中尋找指定指令碼的解釋程式 第二行:建立 名叫code資料夾 第三行:進入建立的資料夾 第四行:for迴圈3次 第四行:建立檔案 第五行:往建立的檔案中寫入資訊 第六行:結束迴圈
mkdir, touch,cd,touch,echo都是系統命令,在命令列下可以直接執行 for, do, done 是shell指令碼語言 for迴圈的語法
原始碼:op_base.sh
編寫Shell
新建一個檔案,副檔名為sh(sh代表shell),副檔名並不影響指令碼執行,見名知意就好,如果你用php,副檔名為php,如果你用Python,副檔名為python
第一行一般是這樣:
#!/usr/bin/php
#!/usr/bin/env python3
#!/usr/bin/env bash
複製程式碼
#!”是一個約定的標記,它告訴系統這個指令碼需要什麼直譯器來執行 /env 是系統的PATH目錄中查詢
執行 Shell 指令碼有兩種方法:
作為可執行程式
chmod +x op_base.sh
./op_base.sh
複製程式碼
第一行設定 op_base.sh可執行許可權 第二行執行op_base.sh
作為引數
/bin/sh op_base.sh
複製程式碼
變數
定義變數時,變數名前不需要加符號和Python一樣但是在PHP語言中變數需要加$,如:
my_name="jack"
my_name='jack';
複製程式碼
ps: 變數名和等號之間不能有空格,變數後面不能有;
Shell中的引號和PHP類似,字串可以用單引號,也可以用雙引號
單引號字串的限制:
- 單引號裡的任何字元都會原樣輸出,單引號字串中的變數是無效的
- 單引號字串中不能出現單引號(對單引號使用轉義符後也不行
雙引號:
- 雙引號裡可以有變數
- 雙引號裡可以出現轉義字元
但是在Python中單引號和雙引號是沒有區別,但是Python 還有三個引號,在三個引號內字元都不會被轉義
使用變數
對於已經定義過的變數,使用的適合在前面新增$
echo $my_name
echo ${my_name}
複製程式碼
變數名外面的花括號是可選的,加不加都行,建議使用第二種形式
註釋
以“#”開頭的行就是註釋,會被直譯器忽略。
多行註釋
sh裡沒有多行註釋,只能每一行加一個#號。就像這樣:
#--------------------------------------------
# Author: jack
# weibo: OO是有情懷的PM
#
# Notes: 10分鐘入門Shell指令碼程式設計
#
# Project home page:
# https://github.com/dpm100/fast_guides
#--------------------------------------------
複製程式碼
字串
字串可以用單引號,也可以用雙引號,也可以不用引號。單雙引號的區別跟PHP類似
Shell不像其他語言有php、python 有很多資料型別,在Shell中常用的資料型別字串數字和字串(ps: 除了數字和字串,也沒啥其它型別好用了,哈哈)
單引號字串的限制:
- 單引號裡的任何字元都會原樣輸出,單引號字串中的變數是無效的
- 單引號字串中不能出現單引號(對單引號使用轉義符後也不行
雙引號:
- 雙引號裡可以有變數
- 雙引號裡可以出現轉義字元
字串操作
拼接字串
my_name="jack";
my_age="20歲"
echo $my_name $my_age
echo $my_name$my_age
複製程式碼
獲取字串長度
echo ${#my_name}
複製程式碼
擷取字串
echo ${my_name:0:2}
複製程式碼
原始碼:op_str.sh
Shell 陣列
定義陣列
在Shell中,用括號來表示陣列,陣列元素用"空格"符號分割開。定義陣列的一般形式為:
name=(name1 name2 name3)
複製程式碼
還可以單獨定義陣列的各個分量:
ary[0]=name1
ary[1]=name2
ary[3]=name3
複製程式碼
ps: 可以不使用連續的下標,而且下標的範圍沒有限制
讀取陣列
讀取陣列元素值的一般格式是:
${陣列名[下標]}
複製程式碼
例如:
echo ${name[0]}
複製程式碼
使用@符號可以獲取陣列中的所有元素,例如:
echo ${name[@]}
複製程式碼
獲取陣列的長度
獲取陣列長度的方法與獲取字串長度的方法相同,例如:
# 取得陣列元素的個數
length=${#name[@]}
echo $length
# 或者
length=${#name[*]}
echo $length
# 取得陣列單個元素的長度
lengthn=${#name[n]}
echo $length
複製程式碼
原始碼:op_arry.sh
Shell 流程控制
和Java、PHP、Python等語言不一樣,sh的流程控制不可為空,如(以下為PHP流程控制寫法):
<?php
if (isset($_GET["q"])) {
search(q);
}
else {
// 不做任何事情
}
複製程式碼
在sh/bash裡可不能這麼寫,如果else分支沒有語句執行,就不要寫這個else
if
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi
複製程式碼
例子:
#!/usr/bin/env bash
a=1
b=2
if [ $a == $b ]
then
echo "a 等於 b"
elif [ $a -gt $b ]
then
echo "a 大於 b"
elif [ $a -lt $b ]
then
echo "a 小於 b"
else
echo "沒有符合的條件"
fi
複製程式碼
原始碼:op_if.sh
for 迴圈
Shell的for迴圈和Python 有點類似
Python的for迴圈
for index in 1,2,3,4,5:
print(index);
複製程式碼
Shell的for迴圈,第一種寫法
for index in 1 2 3 4 5; do
echo "index="$index
done
複製程式碼
Shell的for迴圈,第二種寫法
for ((i=0; i<5; i++)); do
echo "i="$i
done
複製程式碼
原始碼:op_for.sh
while 語句
while迴圈用於不斷執行一系列命令,也用於從輸入檔案中讀取資料;命令通常為測試條件。
int=1
while(( $int<=5 ))
do
echo $int
let "int++"
done
複製程式碼
原始碼:op_while.sh
Shell結合系統命令
sh指令碼結合系統命令便有了強大的威力,在字元處理領域,有grep、awk、sed三劍客,grep負責找出特定的行,awk能將行拆分成多個欄位,sed則可以實現更新插入刪除等寫操作。
例如定時檢測nginx、mysql是否被關閉
path=/var/log
log=${path}/httpd-mysql.log
name=(apache mysql)
exs_init[0]="service httpd start"
exs_init[1]="/etc/init.d/mysqld restart"
for ((i=0; i<2; i++)); do
echo "檢查${name[i]}程式是否存在"
ps -ef|grep ${name[i]} |grep -v grep
if [ $? -eq 0 ]; then
pid=$(pgrep -f ${name[i]})
echo "`date +"%Y-%m-%d %H:%M:%S"` ${name[$i]} is running with pid $pid" >> ${log}
else
$(${exs_init[i]})
echo "`date +"%Y-%m-%d %H:%M:%S"` ${name[$i]} start success" >> ${log}
fi
done
複製程式碼
解釋:檢測 nginx、mysql程式是否存在,如果不存在了會自動重新啟動。 指令碼每次執行會寫日誌的,沒事可以去看看該日誌檔案,如果程式是不是真的經常性不存在,恐怕就要排查一下深層原因了。
原始碼:check_nginx.sh
編輯 /etc/crontab 檔案
crontab -e
複製程式碼
在檔案最後新增一行:
*/5 * * * * /xxx/check_nginx.sh > /dev/null 2>&1
複製程式碼
上表示每 5 分鐘,執行一下指令碼 /xxx/check_nginx.sh,其中xxx代表路徑
/dev/null 2>&1 的意思是該條shell命令將不會輸出任何資訊到控制檯,也不會有任何資訊輸出到檔案中。
# For details see man 4 crontabs
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * command to be executed
複製程式碼
新增完配置,需要重啟才能生效
service crond restart
複製程式碼