本章內容:
- 變量
- 運算
- if語句
- for語句
- while語句
- break、continue
- 實例
shell變量
1、shell變量簡介
變量是任何一種編程語言都必不可少的組成部分,變量用來存放各種數據。腳本語言在定義變量時通常不需要指明類型,直接賦值就可以,Shell 變量也遵循這個規則。
在 Bash shell 中,每一個變量的值都是字符串,無論你給變量賦值時有沒有使用引號,值都會以字符串的形式存儲;這意味着,Bash shell 在默認情況下不會區分變量類型,即使你將整數和小數賦值給變量,它們也會被視為字符串,這一點和大部分的編程語言不同。
2、定義變量
Shell 常用三種定義變量的方式:
variable=value
variable='value' #所見即所得
variable="value" #進行轉義
variable=`cat test` #執行命令將命令輸出賦值給變量
Shell 變量的命名規范和大部分編程語言都一樣:
- 變量名由數字、字母、下划線組成;
- 必須以字母或者下划線開頭;
- 不能使用 Shell 里的關鍵字(通過 help 命令可以查看保留關鍵字)。
3、使用變量
╭─root@localhost.localdomain ~
╰─➤ aa="cjk"
╭─root@localhost.localdomain ~
╰─➤ echo $aa
cjk
╭─root@localhost.localdomain ~
╰─➤ echo ${aa} #推薦給所有變量加上花括號{ },這是個良好的編程習慣
cjk
4、刪除變量
使用 unset 命令可以刪除變量
╭─root@localhost.localdomain ~
╰─➤ aa="cjk"
╭─root@localhost.localdomain ~
╰─➤ echo ${aa}
cjk
╭─root@localhost.localdomain ~
╰─➤ unset aa #unset 命令不能刪除只讀變量
╭─root@localhost.localdomain ~
╰─➤ echo ${aa}
5、變量類型
運行shell時,會同時存在三種變量:
局部變量
局部變量在腳本或命令中定義,僅在當前shell實例中有效,其他shell啟動的程序不能訪問局部變量。
環境變量
所有的程序,包括shell啟動的程序,都能訪問環境變量,有些程序需要環境變量來保證其正常運行。必要的時候shell腳本也可以定義環境變量。
shell變量
shell變量是由shell程序設置的特殊變量。shell變量中有一部分是環境變量,有一部分是局部變量,這些變量保證了shell的正常運行
6、系統變量
在命令行提示符直接執行 env、set 查看系統或環境變量。env 顯示用戶環境變量,set 顯示 Shell 預先定義好的變量以及用戶變量。可以通過 export 導出成用戶變量。一些寫 Shell 腳本時常用的系統變量
系統變量名 | 系統變量意識 |
---|---|
$SHELL | 默認 Shell |
$HOME | 當前用戶家目錄 |
$IFS | 內部字段分隔符 |
$LANG | 默認語言 |
$PATH | 默認可執行程序路徑 |
$PWD | 當前目錄 |
$UID | 當前用戶 ID |
$USER | 當前用戶 |
$HISTSIZE | 歷史命令大小,可通過 HISTTIMEFORMAT 變量設置命令執行時間 |
$RANDOM | 隨機生成一個 0 至 32767 的整數 |
$HOSTNAME | 主機名 |
生成8位隨機數:echo "$RANDOM"|md5sum|cut -c 1-8
7、普通變量和環境變量
- 普通變量定義:VAR=value
- 臨時環境變量定義:export VAR=value
- 變量引用:$VAR
- 區別:Shell 進程的環境變量作用域是 Shell 進程,當 export 導入到系統變量時,則作用域是 Shell 進程及其 Shell 子進程,另開shell無效。
8、特殊變量列表(shell變量)
變量 | 含義 |
---|---|
$0 | 當前腳本的文件名 |
$n | 傳遞給腳本或函數的參數。n 是一個數字,表示第幾個參數。例如,第一個參數是$1,第二個參數是$2。 |
$# | 傳遞給腳本或函數的參數個數。 |
$* | 傳遞給腳本或函數的所有參數。 |
$? | 上個命令的退出狀態,或函數的返回值,成功會返回 0,失敗返回非0 |
$$ | 當前Shell進程ID,對於 Shell 腳本,就是這些腳本所在的進程ID |
實例:
╭─root@localhost.localdomain ~
╰─➤ vim test.sh
...
#!/bin/bash
echo "File Name: $0"
echo "First Parameter : $1"
echo "First Parameter : $2"
echo "Quoted Values: $@"
echo "Quoted Values: $*"
echo "Total Number of Parameters : $#"
...
╭─root@localhost.localdomain ~
╰─➤ bash test.sh hello cjk touch
File Name: test.sh
First Parameter : hello
First Parameter : cjk
Quoted Values: hello cjk touch
Quoted Values: hello cjk touch
Total Number of Parameters : 3
╭─root@localhost.localdomain ~
╰─➤ echo $?
0
╭─root@localhost.localdomain ~
╰─➤ ddd ddd
zsh: command not found: ddd
╭─root@localhost.localdomain ~
╰─➤ echo $?
127
shift 命令 將參數向前移一位
shift n 向前移n位
shell條件表達式與運算符
9、條件表達式
表達式 | 實例 |
---|---|
[ expression ] | [ 1 -eq 1 ] |
[[ expression ]] | [[ 1 -eq 1 ]] |
test expression | test 1 -eq 1 ,等同於[] |
注意:括號中的表達式前后都有空格,否則會報錯!
╭─root@localhost.localdomain ~
╰─➤ [ 1 -eq 1 ] && echo "true" || echo "false"
true
╭─root@localhost.localdomain ~
╰─➤ [ 1 -eq 2 ] && echo "true" || echo "false"
false
╭─root@localhost.localdomain ~
╰─➤ [1 -eq 2] && echo "true" || echo "false"
zsh: bad pattern: [1
10、整數比較符
比較符 | 描述 | 實例 |
---|---|---|
-eq, equal | 等於 | [ 1 -eq 1 ] 為true |
-ne, not equal | 不等於 | [ 1 -ne 1 ] 為false |
-gt, greate than | 大於 | [ 1 -gt 1 ] 為false |
-lt, lesser than | 小於 | [ 1 -lt 1 ] 為false |
-ge, greate or equal | 大於或者等於 | [ 1 -ge 1 ] 為true |
-le, lesser or equal | 小於或者等於 | [ 1 -le 1 ] 為true |
11、字符串比較符
運算符 | 描述 | 實例 |
---|---|---|
== | 等於 | [ “a” == “a” ] 為true |
!= | 不等於 | [ “a” != “a” ] 為false |
-n | 字符串長度不等於 0 為真 | VAR1=1;VAR2=”” [ -n “$VAR1” ]為 true [ -n “$VAR2” ]為 false |
-z | 字符串長度等於 0 為真 | VAR1=1;VAR2=”” [ -z “$VAR1” ]為false [ -z “$VAR2” ]為 true |
注意:使用-n 判斷字符串長度時,變量要加雙引號,養成好習慣,字符串比較時都加上雙引號
12、文件測試
測試符 | 描述 | 實例 |
---|---|---|
-e | 文件或者目錄存在為真 | [ -e path ] path 存在為 true |
-f | 文件存在為真 | [ -f file_path ] 文件存在為 true |
-d | 目錄存在為真 | [ -d dir_path ] 目錄存在為 true |
-r | 有讀權限為真 | [ -r file_path ]file_path有讀權限為真 |
-w | 有寫權限為真 | [ -w file_path ]file_path有寫權限為真 |
-x | 有執行權限為真 | [ -x file_path ]file_path有執行權限為真 |
-s | 文件存在且不為空為真 | [-s file_path]file_path存在且不為空為真 |
13、布爾運算符
運算符 | 描述 | 實例 |
---|---|---|
! | 非關系,條件結果取反 | [ ! 1 -eq 2 ]為true |
-a | 和關系,在[]表達式中使用 | [ 1 -eq 1 -a 2 -eq 2 ]為true 兩者都為真才為真 |
-o | 或關系,在[]表達式中使用 | [ 1 -eq 1 -o 2 -eq 1 ]為true 兩者有一真則為真 |
14、邏輯判斷符
判斷符 | 描述 | 實例 |
---|---|---|
&& | 邏輯和,在[[]]表達式中或判斷表達式是否為真時使用 | [[ 1 -eq 1 && 2 -eq 2 ]]為 true [ 1 -eq 1 ] && echo ‘true’ 如果&&前面的表達式為true則執行后面的 |
|| | 邏輯或,在[[]]表達式中或判斷表達式是否為真時使用 | [[ 1 -eq 1 || 2 -eq 1 ]]為 true [ 1 -eq 2 ] || echo ‘true’ 如果||前面的表達式為false則執行后面的 |
15、整數運算符
運算符 | 描述 |
---|---|
+ | 加法 |
– | 減法 |
* | 乘法 |
/ | 除法 |
% | 取余 |
運算表達式 | 實例 |
---|---|
$(()) | $((1+1)) |
$[] | $[] |
16、其他運算符
命令 | 描述 | 實例 |
---|---|---|
let | 賦值並運算 | let x++;echo $x 每執行一次 x 加 1 let y–;echo $y 每執行一次 y 減 1 let x+=2 每執行一次 x 加 2 let x-=2 每執行一次 x 減 2 |
expr | 乘法*需要\轉義"\*" | expr 1 \* 2 運算符兩邊必須有空格 expr\( 1 + 2\) \* 2 使用雙括號時要轉義 |
if語句
if語句用exit結束
1.1單分支
if 條件表達式 ;then
命令
fi
實例:
#!/bin/bash
read -p "請輸入數字" num
if [ $num -lt 10 ] ;then
echo "${num}是數字兩位數"
fi
...
╭─root@localhost.localdomain ~
╰─➤ bash test.sh
請輸入數字3
3是數字一位數
1.2、多分支
if 條件表達式 ;then
命令
else
命令
fi
實例:
#!/bin/bash
read -p "請輸入數字" num
if [ $num -gt 9 -a $num -lt 100 ] ;then
echo "${num}是數字兩位數"
else
echo "${num}不是數字兩位數"
fi
...
╭─root@localhost.localdomain ~
╰─➤ bash test.sh
請輸入數字56
56是數字兩位數
╭─root@localhost.localdomain ~
╰─➤ bash test.sh
請輸入數字222
222不是數字兩位數
1.3、多分支
if 條件表達式 ;then
命令
elif 條件表達式 ;then
命令
else
命令
fi
實例:
#!/bin/bash
num=`echo $RANDOM`
if [ $num -lt 1000 ];then
echo "$num小於1000"
elif [ $num -ge 1000 -a $num -lt 2000 ];then
echo "$num大於等於1000,小於2000"
elif [ $num -ge 2000 -a $num -lt 3000 ];then
echo "$num大於等於2000,小於3000"
elif [ $num -ge 3000 -a $num -lt 4000 ];then
echo "$num大於等於3000,小於4000"
else
echo "$num大於等於4000"
fi
...
╭─root@localhost.localdomain ~
╰─➤ bash test.sh
24497大於等於4000
╭─root@localhost.localdomain ~
╰─➤ bash test.sh
20763大於等於4000
for 循環
for 變量名 in 取值列表
do
命令
done
實例:
#!/bin/bash
. /etc/init.d/functions
ip=192.168.80.
for i in `seq 10`
do
if ping -c 1 -w 1 $ip$i &>/dev/null;then
echo -n " $ip$i" #-n:作用不換行 ;$ip前有空格
success
echo " "
sleep 1
else
echo -n " $ip$i"
failure
echo " "
sleep 1
fi
done
...
╭─root@localhost.localdomain ~
╰─➤ bash test.sh
192.168.80.1 [ OK ]
192.168.80.2 [ OK ]
192.168.80.3 [ OK ]
192.168.80.4 [ OK ]
192.168.80.5 [FAILED]
192.168.80.6 [FAILED]
192.168.80.7 [FAILED]
192.168.80.8 [FAILED]
192.168.80.9 [FAILED]
192.168.80.10 [FAILED]
while循環
while 條件表達式 ; do
命令
done
3.1、一般循環
當條件表達式為 false 時,終止循環
實例:
#!/bin/bash
N=0
while [ $N -lt 5 ]; do
echo $N
let N++
done
...
╭─root@localhost.localdomain ~
╰─➤ bash test1.sh
0
1
2
3
4
3.2、死循環
條件表達式為 true,將會產生死循環
#!/bin/bash
while true ;do
echo "hello"
sleep 1
done
...
╭─root@localhost.localdomain ~
╰─➤ bash test2.sh
hello
hello
hello
hello
hello
^C
- 命令行中輸入 nohup bash naolie.sh & 即可在后台持續運行該腳本
break和continue語句
- continue 與 break 語句只能循環語句中使用;
- break:終止循環,運行針跳至done后;
- continue :跳出當前循環,運行針跳至do后,開始下一循環;
演示:
break語句
#!/bin/bash
N=0
while [ $N -lt 10 ]; do
let N++
if [ $N -eq 5 ]; then
break
fi
echo $N
done
...
╭─root@localhost.localdomain ~
╰─➤ bash test1.sh
1
2
3
4
continue語句
#!/bin/bash
N=0
while [ $N -lt 10 ]; do
let N++
if [ $N -eq 5 ]; then
continue
fi
echo $N
done
...
╭─root@localhost.localdomain ~
╰─➤ bash test1.sh
1
2
3
4
6
7
8
9
10
實例拓展:
實例1:
#!/bin/bash
echo "主機名:`hostname`"
echo "IP地址:`ip a | grep "global" | cut -d "/" -f 1 | cut -d "t" -f 2 | tr -d " "`"
echo "操作系統版本:`cat /etc/redhat-release`"
echo "內核版本:`uname -r`"
echo "CPU信息:`lscpu | grep -i "Model name" | cut -c "24-69"`"
echo "內存總大小:`free -h | grep "Mem" | cut -d "M" -f 2 | tr -d "em: "`M"
...
╭─root@localhost.localdomain ~
╰─➤ bash test6.sh
主機名:localhost.localdomain
IP地址:192.168.80.3
操作系統版本:CentOS Linux release 7.3.1611 (Core)
內核版本:3.10.0-514.el7.x86_64
CPU信息:Intel(R) Core(TM) i5-4210M CPU @ 2.60GHz
內存總大小:976M
...
實例二:
#!/bin/bash
sum=0
for i in `find / -type f -a -name "*.sh"`
do
size=`ls -l $i | cut -d " " -f 5`
let sum+=size
done
echo ".sh結尾的總大小$(($sum/1024))kb"
...
╭─root@localhost.localdomain ~
╰─➤ bash test7.sh
.sh結尾的總大小1098kb
實例三:創建100個用戶並設置6位隨機密碼
[root@du ~]# cat test9.sh
#!/bin/bash
#!/bin/bash
for i in `seq 10`
do
useradd user$i
pass=`echo $RANDOM | md5sum | cut -c 1-6`
echo "$pass" | passwd --stdin "user$i"
echo -e "賬戶:user$i\n密碼:$pass" >> /root/passwd
done
##執行結果:
[root@du ~]# cat passwd
賬戶:user1
密碼:69a70a
賬戶:user2
密碼:444c02
賬戶:user3
密碼:6b381f
賬戶:user4
密碼:28d8fd
實例四:找出100以內的質數
#!/bin/bash
for i in `seq 100`
do
for((j=2;j<i;j++))
do
[ $((i%j)) -eq 0 ] && break
done
[ $j -eq $i ] && echo $i
done
## 執行
╭─root@localhost.localdomain ~
╰─➤ bash test.sh
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97
實例五:逐行讀取文件
#!/bin/bash
cat $1 | while read line
do
echo “$line”
sleep 1
done
## 執行
╭─root@localhost.localdomain ~
╰─➤ bash readtest.sh /etc/passwd
“root:x:0:0:root:/root:/bin/zsh”
“bin:x:1:1:bin:/bin:/sbin/nologin”
“daemon:x:2:2:daemon:/sbin:/sbin/nologin”
“adm:x:3:4:adm:/var/adm:/sbin/nologin”
“lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin”
^C#
實例六:shell腳本工整化輸出,表格形式輸出
摘自:https://blog.csdn.net/qq_41228463/article/details/80720772
#!/bin/bash
table=""
#設置行,可以是表頭,也可以是表格內容。
#如果是表格內容,“—”表示空值
function setRow(){
value=$*
table=${table}"|${value// /#|}#|\n"
}
#行分隔線
#入參:表格的列數。如表格有5列,則入參為5
function splitLine(){
local num=`expr $1 + 2`
split=`seq -s '+#' $num | sed 's/[0-9]//g'` # 生成連續個的+#
table=${table}"${split}\n"
}
#繪制表格
#入參:table
function setTable(){
echo -e $1|column -s "#" -t|awk '{if($0 ~ /^+/){gsub(" ","-",$0);print $0}else{print $0}}'
}
if [ "$SHLVL" -eq "2" ]
then
table=""
splitLine 3
setRow "姓名" "性別" "年齡"
splitLine 3
setRow "Tom" "male" "10"
setRow "Nacy" "female" "-"
splitLine 3
setTable ${table}
fi
##輸出結果
#bash test.sh
+------+--------+------+--
|姓名 |性別 |年齡 |
+------+--------+------+--
|Tom |male |10 |
|Nacy |female |- |
+------+--------+------+--