Shell編程
一.程序簡介
程序
程序:算法+數據結構
數據結構:數據在計算機中的類型和組織方式
算法:處理數據的方式
面向過程:以指令爲中心,數據服務於指令
面向對象:以數據爲中心,指令服務於數據
計算機:二進制執行
高級編程語言:
編譯:高級語言->編譯器->機器代碼->執行
解釋:高級語言->執行->解釋器->機器代碼 shell
三大邏輯
順序、循環、選擇
二.shell腳本
1.格式
格式要求:首行shebang機制
#!/bin/bash 指定shell類型
# 註釋
程序名,作用說明,版本信息,作者信息
bash -n 檢查語法錯誤
bash -x 跟蹤調試腳本的執行過程
2.變量
變量的類型:
字符、整型
強類型
弱類型
不需要聲明變量類型
不支持浮點型
都以字符串的形式存儲
命名規則:
不能是內部命令、系統關鍵字
字母、數字、下劃線
不能以數字開頭
定義變量
a=linux
a='linux'
a="linux"
上面三個都是把linux這個字符串賦值給變量a,如果賦值的一方當中沒有空格,則不用引號,如果有空格則必須用引號。
使用變量
echo $a
echo ${a}
調用變量a,在變量前面加上$即可,變量用{}括起來是個良好的習慣
已經定義的變量也可以重新賦值
a=centos
unset a 刪除變量
readonly a 只讀變量,不能修改
單雙引號的區別
單引號 '' 強引用,單引號裏所有內容都作爲字符輸出
雙引號 "" 若引用,雙引號裏有變量的時候,會讀取變量值輸出,而不是直接輸出
把命令執行結果賦值給變量
a=`cat /etc/fstab` 使用反向單引號
a=$(cat /etc/fstab) 使用$()
反向單引號容易和單引號混淆,因此推薦使用$()
局部變量和全局變量
局部變量:生效範圍是當前shell進程
全局變量:生效範圍是當前shell及其子進程
export a 聲明全局變量
set 顯示變量,自定義和系統自帶的
export 或 declare 顯示環境變量
echo $PPID 顯示父進程編號
pstree -p 顯示進程信息
source 運行的腳本在本bash環境下,會修改某些當前bash下的環境。
bash 運行腳本時會新開一個bash,爲當前bash的子進程,不會影響當前環境
SHLVL 變量,shell 的嵌套深度
echo $_ 上一個命令的最後一個字符串
unset name 刪除變量,除了只讀變量
readonly 查看只讀變量 declare -r
(umask=0022;touch a)
() 不開啓子進程
{} 開啓子進程
位置變量
$$ 當前shell的ID
$1 第一個參數
$* 所有參數,認爲所有參數是一個整體
$@ 所有參數,認爲所有參數是獨立的個體
$# 參數數量
$0 當前腳本的文件名
10以上的加{}
shift n 變量按順序往前移動n個變量
set -- 清除變量
退出狀態
$? 變量保存最近(前一個)的命令退出狀態
0 代表成功,1-255 代表失敗
腳本里指定返回值 exit 10
2.運算
bash支持算術運算、關係運算、布爾運算、字符串運算和文件測試運算等
算術運算
expr 2 + 4
echo `expr 2 + 4
a=`expr 2 + 4`
c=`expr $a + $b`
expr是一款表達式計算工具,數值和運算符之間必須有空格,調用整個表達式的時候記得加``
let sum=x+y
$[x+y]
$((x+y))
expr 2 + 3 expr是一個命令
declare -i n=10 指定n是個整數,聲明變量
-= += -- ++
運算符 | 說明 | 舉例 |
---|---|---|
+ | 加法 | `expr $a + $b |
- | 減法 | `expr $a - $b |
* | 乘法 | `expr $a \* $b |
/ | 除法 | `expr $a / $b |
% | 取餘 | `expr $a % $b |
= | 賦值 | a=$b |
== | 比較兩個數字是否相等 | [ $a == $b ] |
!= | 比較兩個數是否不等 | [ $a != $b ] |
表達式和[ ]之間需要有空格
邏輯運算
true 1 ;false 0;
與 & 有0即0
或 | 有1即1
非 ! 取反
短路與 && 前一個爲假則不再判斷第二個
短路或 || 前一個爲真則不再判斷第二個
異或 ^ 相同爲假,相異爲真
同或 相同爲真,相異爲假
測試命令:
test 不支持正則表達式,沒值就爲假,變量加“”
[[]] 支持正則表達式
[] 有值就爲真
[] 和變量之間要加空格
幾種括號的用法
(; ; ) 幾個命令一起執行,開啓子shell
{; ; } 幾個命令一起執行,不開啓子shell,前後空格,最後一個加;號
[] 邏輯判斷,不支持正則表達式
[[]] 邏輯判斷,支持正則表達式,一般用[]
=~ 匹配,字符串不要加"",支持正則表達式
!= 不等
== 相等,字符串不要加"",支持通配符
關係符運算
數值測試,不支持字符
運算符 | 說明 | 全稱 |
---|---|---|
-gt | 是否大於 | greater than |
-ge | 是否大於等於 | greater than equal |
-eq | 是否等於 | equal |
-ne | 是否不等於 | no equal |
-lt | 是否小於 | less than |
-le | 是否小於等於 | less equal |
字符串測試
= 是否等於
> ascii碼是否大於
< 是否小於
!= 是否不等於
=~ 左側字符串是否能夠被右側的pattern匹配,一般用於[[]]中
-z "string" 字符串是否爲空,空爲真,非空爲假
-n "string" 字符串是否不空,不空爲真,空位假
文件測試
-a / -e file :文件存在性測試,存在未真,否則爲假
-b 是否存在且爲塊設備文件
-c 是否存在且爲字符設備文件
-d 是否存在且爲目錄文件
-f 是否存在且爲普通文件
-h / -L :存在且爲鏈接文件
-p 是否存在且爲命名管道文件
-S 是否存在且爲套接字文件
權限測試
-r 是否存在且可讀
-w 是否存在且可寫
-x 是否存在且可執行
-u 是否存在且擁有suid權限
-g 是否存在且擁有sgid權限
-k 是否存在且擁有sticky權限
文件屬性
-s 是否存在且爲非空
-t 文件描述符是否在某終端打開
-N 文件自從上一次被讀取之後是否被修改
-O 當前有效用戶是否爲文件時屬主
-G 當前用戶是否爲文件屬組
雙目測試
file1 -ef file2:1是否是2的硬鏈接
file1 -nt file2:1是否新於file2
file1 -ot file2:1是否舊於file2
-a 並且
-o 或者
! 非
3.字符串
單引號
str='this is a string'
單引號裏的任何字符都會原樣輸出,單引號裏的變量是無效的
單引號字符串中不能出現單引號,對單引號轉義後也不行
雙引號
str="you name is $name"
雙引號裏可以有變量
雙引號裏可以出現轉義字符
拼接字符串
firstname="zhang"
lastname="hw"
echo $firstname $lastname 輸出:zhanghw
獲取字符串長度
str="abcd"
echo ${#str} 輸出:4
提取子字符串
str="daxiong is the best girl"
echo ${str:1:4} 1:4 起始字符到終止字符,由0開始
查找子字符串
str="daxiong is the best girl"
echo `expr index "$str" is`
4.數組
只支持一維數組,沒有限定數組大小。數組元素下表從0開始,下表可以是整數或算術表達式,其值應大於或等於0
定義
用括號來定義數組,各個元素間用空格分開,如下:
array_name=(value0 value1 value2)
單獨定義
array_name[0]=value0
array_name[1]=value1
引用
${array_name[index]}
a=${array_name[0]}
${array_name[@}}
${array_name[*]} @或* 可以獲取數組中的所有元素
獲取數組的長度
a=${#array_name[@]} 取得數組元素的個數 @或*都可以
a=${#array_name[n]} 取得下標爲n的元素的長度
5.shell printf
printf命令用於格式化輸出,printf由POSIX標準所定義,移植性比echo好
printf "hello\n" 輸出字符串,printf不自帶換行,需要在字符串最後添加\n
printf format-string [arguments]
format-string爲雙引號
$ printf "%d %s\n" 1 "abc"
1 ab
格式只指定了一個參數,但多出的參數仍然會按照該格式輸出,format-string 被重用
$ printf %s abc def
abcdef
$ printf "%s\n" abc def
abc
def
$ printf "%s %s %s\n" a b c d e f g h i j
a b c
d e f
g h i
j
如果沒有 arguments,那麼 %s 用NULL代替,%d 用 0 代替
$ printf "%s and %d \n"
and 0
6.if else 語句
- if...fi
- if...else...fi
- if...elif...else...fi
最後必須以fi結尾來閉合
if 語句的用法
if [ expression ]
then
Statement(s) to be executed if expression is true
fi
如果expression返回ture,then後面的語句將會被執行;如果返回false則跳出循環
if..else...fi 語句的用法
if [ expression ]
then
Statement(s) to be executed if expression is true
else
Statement(s) to be executed if expression is not true
fi
如果expression返回true則執行then後面的語句,否則執行else後面的語句
if...elif...fi 語句的用法
if [ expression 1 ]
then
Statement(s) to be executed if expression 1 is true
elif [ expression 2 ]
then
Statement(s) to be executed if expression 2 is true
else
Statement(s) to be executed if no expression is true
fi
哪一個expression 的值爲true,就執行那個expression後面的語句,如果都爲false則執行else後面的語句
7.for循環
for varibale in 列表
do
command1
command2
...
conmmandN
done
列表是一組數值(數值、字符串等)組成的序列,每個值通過空格分格。每循環一次,就將列表中的下一個值賦給變量
in 列表是可選的,如果不用它,for循環使用命令行的位置參數
seq 列表的產生
wait
8.while循環
-
while循環用於不斷執行一系列命令,也用於從輸入文件中讀取數據;命令通常爲測試條件
while command
do
Statement(s) to be executed if command is true
done
: 代表true的意思
9.until循環
-
直到型循環,當執行結果爲true時才跳出循環。
until command
do
Statement(s) to be executed until command is true
done
10.continue
跳過本次循環
> break [N] 直接結束第N層的本輪循環,而直接進入下一輪判斷,最內層爲第1層,默認值爲1
while command1
do
if command2
then
continue
fi
done
11.break
跳出整個循環
break [N] 提前結束第N層循環,最內層爲第一層
while command1
do
if command2
then
break
fi
done
12.shift
shift [n]
將參量列表list左移指定次數,缺省爲左移一次。列表list一旦被移動,最左端的那個參數就從列表中刪除。
#!/bin/bash
#step through all the positional parameters
until [ -z "$1" ]
do
echo "$1"
shift
done
echo
13.select
select variable in list
do
循環體命令
done
select 循環主要用於創建菜單,按數字順序排列的菜單項將顯示在
標準錯誤上,並顯示 PS3 提示符,等待用戶輸入
用戶輸入菜單列表中的某個數字,執行相應的命令
用戶輸入被保存在內置變量 REPLY 中
select 是個無限循環,因此要記住用 break 命令退出循環,或用
exit 命令終止腳本。也可以按 ctrl+c 退出循環
select 經常和 case 聯合使用
與 for 循環類似,可以省略 in list,此時使用位置參量
14.while特殊用法
while read line
do
循環體
done < /path/from/somefile
依次讀取/path/from/somelife 文件中的每一行,且將行賦值給變量line
15.case...esac
- case...esca 是一種多分支選擇結構
-
case語句匹配一個值或一個模式,如果匹配成功,執行相匹配的命令。
case VALUE in
mode1)
command 1
command 2
command 3
;;
mode2)
command1
command2
command3
;;
esac
取值後面必須爲關鍵字in,每一模式必須以右括號結束。取值可以爲變量或常數。
;; 與其他語言中的break 類似,意思是跳到整個case語句的最後。