1.簡介
shell腳本執行方式Shell 是一個用 C 語言編寫的程序,通過 Shell 用戶可以訪問操作系統內核服務。它類似於 DOS 下的 command 和后來的 cmd.exe。Shell 既是一種命令語言,又是一種程序設計語言。
Shell script 是一種為 shell 編寫的腳本程序。Shell 編程一般指 shell腳本編程,不是指開發 shell 自身。
Shell 編程跟 java、php 編程一樣,只要有一個能編寫代碼的文本編輯器和一個能解釋執行的腳本解釋器就可以了。
Linux 的 Shell 種類眾多,一個系統可以存在多個 shell,可以通過 cat /etc/shells 命令查看系統中安裝的 shell。
Bash 由於易用和免費,在日常工作中被廣泛使用。同時,Bash 也是大多數Linux 系統默認的 Shell。
2.快速入門
-
1.#!是一個約定的標記,它告訴系統這個腳本需要什么解釋器來執行,即使用哪一種 Shell。注意,在shell腳本中除了第一行的#表示特殊格式外,其他地方的#一般表示注釋。
echo命令用於向窗口輸出文本。touch hello.sh # 新建一個.sh文件 vim hello.sh # vim編輯此文件 #文件里編寫下面 #!/bin/bash echo 'hello world'
3.解釋器
- Java需要虛擬機解釋器, 同理 shell腳本也需要解析器,查看Linux系統支持的解釋器:
cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/bin/dash
/bin/tcsh
/bin/csh
- 4.常見Shell解釋器
- sh:的全稱是Bourne shell,由 AT&T 公司的 Steve Bourne開發,為了紀念他,就用他的名字命名了。sh 是UNIX 上的標准 shell,很多 UNIX 版本都配有 sh。sh 是第一個流行的 Shell。
- Bash:從名稱可以看出是Bsh的升級版本,是著名的開源軟件項目,目前大多數的Linux版本都使用Bash作為默認的Shell程序,當運行Shell程序時,實際運行的是Bash程序
- Csh:是因使用C語言的語法風格而得名,在用戶的命令行交互界面上進行了很多改進,並增加了歷史,別名,文件名替換,作業掏等功能,相比Bsh,Csh在更加適用為 用戶提供命令交互操作
在現代的 Linux上,sh 已經被 bash 代替,/bin/sh往往是指向/bin/bash的符號鏈接。
如果你希望查看當前 Linux的默認 Shell,那么可以輸出 SHELL 環境變量
[root@node1 shell]# echo $SHELL
/bin/bash
5.shell腳本執行方式
- shell腳本有三種執行方式
- sh執行
sh執行,進入腳本的工作目錄,然后使用對應的sh或bash來執行腳本,這種執行方式,腳本文件不需要具有可執行權限
[root@node1 ~]#sh hello.sh
hello world - 工作目錄執行
執行腳本時,先進入到腳本所在的目錄,然后使用 ./腳本方式執行,這種執行方式,必須保證腳本文件具有可執行權限
[root@node1 shell]# chmod 777 hello.sh
[root@node1 shell]# ./hello.sh
hello world - 絕對路徑執行
絕對路徑中執行,指的是直接從根目錄/到腳本目錄的絕對路徑,這種執行方式,必須保證腳本文件具有可執行權限
[root@node1 ~]# /root/hello.sh
hello
- sh執行
6.shell的數據類型
-
字符串:
字符串是shell編程中最常用最有用的數據類型,字符串可以用單引號,也可以用雙引號,也可以不用引號。建議使用雙引號,因為雙引號里可以有變量和特殊字符,可以按照變量和特殊字符去使用。 -
整數型:
在Shell中所有的變量默認都是字符串型。默認情況下,所有的數值都是不能進行運算的,如果想要進行數學運算,可以使用“$((運算式))”或“$[運算式]”方式運算。
7.變量
-
shell變量是一種很“弱”的變量,默認情況下,一個變量保存一個串,shell不關心這個串是什么含義。所以若要進行數學運算,必須使用一些命令例如let、declare、expr、雙括號等。
在shell中有3種變量:用戶變量、環境變量、特殊變量,其中用戶變量在編程過程中使用量最多,環境變量主要是在程序運行時需要設置,特殊變量在對參數判斷和命令返回值判斷時會使用。 -
變量的定義需遵循的規則
- 變量名可以由字母、數字和下畫線組成,但是不能以數字開頭。
- 在 Bash中,變量的默認類型都是字符串型,如果要進行數值運算,則必須使用特殊命令。
- 變量用等號"="連接值,"="左右兩側不能有空格。
- 變量值中如果有空格,則需要使用單引號或雙引號包含,如 test="hello world!"。雙引號括起 來的內容"$"和反引號者都擁有特殊含義,而單引號括起來的內容都是普通字符。
- 在變量值中,可以使用轉義符""。
- 不能使用bash里的關鍵字(可用help命令查看保留關鍵字)。
8.用戶變量
-
定義變量
在對變量賦於字符串值時,建議使用引號將其包裹。如果字符串中存在空格,請一定要使用單引號或雙引號將整個內容包裹。注意:單引號里的內容原封不動的輸出,雙引號里有變量的調用則會調用變量
[root@node1 ~]# username="itcast" -
訪問變量
要對變量進行調用時,在變量名前加美元符號$
[root@node1 ~]# echo $username
itcast
如果需要增加變量的值,那么可以進行變量值的疊加。不過變量需要用雙引號包含"$變量名"或${變量名}
[root@node1 ~]# echo "$username"db.log
itcastdb.log
[root@node1 ~]# echo ${username}db.log
itcastdb.log -
測試腳本
腳本內容
#! /bin/bash
string="I am shell"
num=5
echo "a=${num},string=${string}"
執行腳本
[root@node1 ~]# sh test1.sh
a=5,string=I am shell
- 變量的其他賦值方式
1)可以使用read關鍵字從鍵盤獲取內容賦值給變量
2)可以通過$(linux命令)或者$linux命令
來執行linux命令,並將命令的執行結果賦值給變量
腳本內容
#! /bin/bash
echo "who are you?"
read pwd #從鍵盤獲取變量的值
pwd_string=$(pwd) #將當前的絕對路徑賦值給pwd_string變量
date_string=`date` #將當前時間賦值給date_string變量
echo "hello, $name"
echo $pwd_string
echo $date_string
執行腳本
[root@node1 shell]# sh test2.sh
who are you?
itcast
hello, itcast
/export/data/shell
2021年 10月 25日 星期日 20:50:21 CST
- 只讀變量
使用 readonly 命令可以將變量定義為只讀變量,只讀變量的值不能被改變。
下面的例子嘗試更改只讀變量,結果報錯:
#!/bin/bash
jdUrl="http://www.jd.com"
readonly jdUrl
jdUrl="http://www.jingdong.com"
運行腳本,結果如下:
/bin/sh: NAME: This variable is read only.
- 刪除變量
使用unset命令可以刪除變量
unset variable_name
變量被刪除后不能再次使用。unset 命令不能刪除只讀變量。
#!/bin/sh
taobaoUrl="http://www.taobao.com"
unset taobaoUrl
echo $taobaoUrl
以上實例執行將沒有任何輸出。
- 環境變量
當shell程序啟動時,都自動設置一組變量,這組變量就是環境變量。shell中的所有命令都可以使用這些變量,環境變量可以在/etc/profile中設置,環境變量的名字習慣上使用大寫字母- 常見的環境變量
PATH 決定了shell將到哪些目錄中尋找命令或程序
HOME 當前用戶主目錄
HISTSIZE 歷史記錄數
LOGNAME 當前用戶的登錄名
HOSTNAME 指主機的名稱
SHELL 當前用戶Shell類型
LANGUGE 語言相關的環境變量,多語言可以修改此環境變量
MAIL 當前用戶的郵件存放目錄
PS1 基本提示符,對於root用戶是#,對於普通用戶是$
可以使用env命令查看所有的系統環境變量
- 常見的環境變量
[root@node1 shell]# env
XDG_SESSION_ID=2
HOSTNAME=node1
SELINUX_ROLE_REQUESTED=
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=192.168.88.5 8047 22
CONDA_SHLVL=0
SELINUX_USE_CURRENT_RANGE=
SSH_TTY=/dev/pts/0
USER=root
- 自定義環境變量
- vim /etc/profile ,在文件末尾加上要定義的環境變量,語法如下:
export 變量名=變量值
export SERVICE_HOST=www.itcast.cn - wq 退出
- source /etc/profile
- 輸入 env 查看環境變量,是否有自己定義的環境變量。
- 使用環境變量
環境變量的使用方式和普通變量是一樣的:$環境變量名
[root@node1 shell]# echo $SERVICE_HOST
www.itcast.cn
- 特殊變量
我們可以在執行 Shell 腳本時,向腳本傳遞參數,這時候可以使用特殊變量來獲取參數,Shell常用的特殊變量如下
$# 命令行參數的個數
$n $1表示第一個參數,$2表示第二個參數
$0 當前程序的名稱
$? 前一個函數的返回碼
$* 以“參數1 參數2 。。。”形式保存所有參數
$@ 同$*
$$ 本程序的PID
$! 上一個命令的PID
以下實例我們向腳本傳遞三個參數,並分別輸出,其中 $0 為執行的文件名:
#!/bin/bash
echo "Shell 傳遞參數實例!";
echo "執行的文件名:$0";
echo "第一個參數為:$1";
echo "第二個參數為:$2";
echo "第三個參數為:$3";
echo "參數個數為:$#";
echo "傳遞的參數作為一個字符串顯示*:$*";
執行腳本
[root@node1 ~]# chmod +x test5.sh
[root@node1 ~]# test5.sh aaa bbb ccc
Shell 傳遞參數實例!
執行的文件名:test5.sh
第一個參數為:aaa
第二個參數為:bbb
第三個參數為:ccc
參數個數為:3
傳遞的參數作為一個字符串顯示*:aaa bbb ccc
$* 與 $@ 區別:
相同點:都是引用所有參數。
不同點:只有在雙引號中體現出來。假設在腳本運行時寫了三個參數 1、2、3,,則 " * " 等價於 "1 2 3"(傳遞了一個參數),而 "@" 等價於 "1" "2" "3"(傳遞了三個參數)。
9.字符串
字符串是shell編程中最常用最有用的數據類型(除了數字和字符串,也沒啥其它類型好用了),字符串可以用單引號,也可以用雙引號,也可以不用引號。
-
單引號
name='錢學森'
str='我很崇拜$name'
echo $str
輸出結果為:
我很崇拜$name
單引號字符串的限制:
單引號里的任何字符都會原樣輸出,單引號字符串中的變量是無效的,單引號字串中不能出現單獨一個的單引號(對單引號使用轉義符后也不行),但可成對出現,作為字符串拼接使用。 -
拼接字符串
#腳本內容
#!/bin/bash
yourname="吳恩達"
wenhou_1="你好,$yourname ."
wenhou_2="你好,"$yourname" ."
wenhou_3="你好,\"$yourname\" ."
echo $wenhou_1 $wenhou_2 $wenhou_3
輸出結果為:
你好,吳恩達 . 你好,吳恩達 . 你好,"吳恩達" .
- 獲取字符串長度
#!/bin/bash
string="jobs"
echo ${string} # 輸出結果: jobs
echo ${#string} # 輸出結果: 4
- 提取字符串
以下實例從字符串第 2 個字符開始截取 4 個字符:
#!/bin/bash
str="敢於亮劍決不后退"
echo ${str:2:2} # 輸出結果為: 亮劍 :2:2 從第二個位置開始切.步長為2
- 查找子字符串
查找字符 i 或 o 的位置(哪個字母先出現就計算哪個):#!/bin/bash string="i am a boy" echo `expr index "$string" am` # 輸出是: 3 `是反引號
10.流程控制
-
算術運算符
Shell 和其他編程一樣,支持包括:算術、關系、布爾、字符串等運算符。原生 bash 不支持簡單的數學運算,但是可以通過其他命令來實現,例如expr。expr 是一款表達式計算工具,使用它能完成表達式的求值操作。
兩個數相加:
val=expr 2+2
echo $val
注意:
表達式和運算符之間要有空格,例如 2+2 是不對的,必須寫成 2 + 2。
完整的表達式要被
下表列出了常用的算術運算符,假定變量 a為10,變量b為20:
expr $a + $b
結果為 30。
expr $a - $b
結果為 -10。
expr $a \* $b
結果為 200。
expr $b / $a
結果為 2
expr $b % $a
結果為 0
a=$b 將把變量 b 的值賦給 a。
[ a == b ] 返回 false
[ a != b ] 返回 true。
注意:條件表達式要放在方括號之間,並且要有空格,例如: [a==b] 是錯誤的,必須寫成 [ a == b ]。 -
數字
-eq 檢測兩個數是否相等,相等返回 true。
-ne 檢測兩個數是否不相等,不相等返回 true。
-gt 檢測左邊的數是否大於右邊的,如果是,則返回 true
-lt 檢測左邊的數是否小於右邊的,如果是,則返回 true。
-ge 檢測左邊的數是否大於等於右邊的,如果是,則返回 true。
-le 檢測左邊的數是否小於等於右邊的,如果是,則返回 true。 -
字符串
-n STRING 字符串長度不為0
-z STRING 字符串長度為0
= 判斷兩個字符串是否一樣
!= 判斷兩個字符串是否不一樣 -
文件
-f 存在且是普通文件
-d 存在且是目錄
-h 存在且是符號鏈接
-e 文件存在
-r 文件存在並且可讀
-w 文件存在並且可寫
-z 文件存在並且可執行 -
if語句
-
判斷當前系統是否有多個ssh進程,如果有則打印true
if [ $(ps -ef | grep -c "ssh") -gt 1 ] then echo "true" fi
-
判斷/media/cdrom文件是否存在,若不存在就去創建這個目錄(空格一定要注意!!!)
#!/bin/bash DIR="/media/cdrom" if [ ! -e $DIR ] then mkdir -p $DIR fi
-
-
if else
#!/bin/bash “”"Enter your age(1-100):" age if [ $age -ge 18 ] then echo '已經成年!' else echo '未成年!' fi
-
if else-if else
#!/bin/bash echo "請輸入a的值:" read a echo "請輸入b的值:" read b 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
輸入成績,判斷成績“優”“良”“中”
#! /bin/bash read -p "Enter your score(0-100):" n #-p參數表示給出提示信息 if [ $n -ge 85 ] && [ $n -le 100 ] ; then echo "優" elif [ $n -ge 70 ] && [ $n -le 84 ] ; then echo "良" elif [ $n -ge 60 ] && [ $n -le 69 ] ; then echo "中" else echo "差" fi
-
for
當變量值在列表里,for循環即執行一次所有命令,使用變量名獲取列表中的當前取值。命令可為任何有效的shell命令和語句。in列表可以包含替換、字符串和文件名。
in列表是可選的,如果不用它,for循環使用命令行的位置參數。- 順序輸出當前列表中的數字
#!/bin/bash for loop in 1 2 3 4 5 do echo "The value is: $loop" done 輸出結果: The value is: 1 The value is: 2 The value is: 3 The value is: 4 The value is: 5
- 順序輸出字符串中的字符
#!/bin/bash for str in 'This is a string' do echo $str done 輸出結果: This is a string
- 打印/root目錄下所有文件的名字
#!/bin/bash for file in $(ls /root) do echo $file done
- 求1-100的和
#!/bin/bash s=0 #從1加到100 for(( i=1;i<=100;i=i+1)) #定義循環100次 do #每次循環給變量s賦值 s=$(($s+$i)) done #輸出從1加到100的和 echo "The sum of 1+2+..+100 is : $s"
- 順序輸出當前列表中的數字
-
while循環
#!/bin/bash num=1 while(( $num<=5 )) do echo $num let "num++" done
-
case語句
#!/bin/bash while : do echo -n "輸入 1 到 5 之間的數字:" read aNum case $aNum in 1|2|3|4|5) echo "你輸入的數字為 $aNum!" ;; *) echo "你輸入的數字不是 1 到 5 之間的! 游戲結束" break ;; esac done
11.函數
```
#!/bin/bash
funWithParam(){
echo "第一個參數為 $1 !"
echo "第二個參數為 $2 !"
echo "第十個參數為 $10 !"
echo "第十個參數為 ${10} !"
echo "第十一個參數為 ${11} !"
echo "參數總數有 $# 個!"
echo "作為一個字符串輸出所有參數 $* !"
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73
輸出結果:
第一個參數為 1 !
第二個參數為 2 !
第十個參數為 10 !
第十個參數為 34 !
第十一個參數為 73 !
參數總數有 11 個!
作為一個字符串輸出所有參數 1 2 3 4 5 6 7 8 9 34 73
```
12.數組
-
定義數組
數組中可以存放多個值。Bash Shell 只支持一維數組(不支持多維數組),初始化時不需要定義數組大小(與 PHP 類似)。
與大部分編程語言類似,數組元素的下標由0開始。
Shell 數組用括號來表示,元素用"空格"符號分割開,語法格式如下:
array_name=(value1 ... valuen) -
讀取數組
${array_name[index]} -
獲取數組中的所有元素
#!/bin/bash my_array[0]=“A” my_array[1]=“B” my_array[2]=“C” my_array[3]=“D” echo "數組的元素為: ${my_array[*]}" echo "數組的元素為: ${my_array[@]}" 輸出: 數組的元素為: A B C D 數組的元素為: A B C D
-
獲取數組的長度
echo "數組的元素個數為: ${#my_array[*]}"
echo "數組的元素個數為: ${#my_array[@]}" -
遍歷數組
#!/bin/bash my_arr=(AA BB CC) for var in ${my_arr[*]} do echo $var done 或者 #!/bin/bash my_arr=(AA BB CC) my_arr_num=${#my_arr[*]} for((i=0;i<my_arr_num;i++)); do echo "-----------------------------" echo ${my_arr[$i]} done
13.加載其它文件的變量
和其他語言一樣,Shell 也可以包含外部腳本。這樣可以很方便的封裝一些公用的代碼作為一個獨立的文件。
Shell 文件包含的語法格式如下:
. filename # 注意點號(.)和文件名中間有一空格
或
source filename
例:
source ./test1.sh # 加載test1.sh 的文件內容