關於shell編程需要記憶(基礎)
寫完shell腳本要用chmod命令加上x(執行)權限
一、shell基礎
一、通配符
文件名的擴展成爲通配,通配定義了一套使用特殊字符的規則。當輸入文件名作爲參數的命令時,可以使用特定的通配符去匹配多個文件
表1-1-1 常用的通配符
符號 | 含義 |
---|---|
* | 匹配任意字符的0次或多次出現 |
? | 匹配任意零個或單個字符 |
[ ] | 匹配字符串中所限定的任何一個字符 |
[^ ]或[! ] | 表示反向選擇,匹配不在該字符串的任意字符 |
{string1,string2,…} | 匹配其中一個指定的字符串 |
1.*(星號)
eg:匹配所有以".png"結尾的,星號可放在任意位置,匹配任意一段字符。
ls *.png
2.?(問號)
?匹配任意單個字符
?*y匹配以任意單個字符開頭以*y結尾的文件名
總而言之:?與*號不同,?只能匹配一個字符
3.[](一對方括號)
[ .]中無論有多少個字符,都只代表某一個字符。例如:[hfchg]匹配以*[ ]中**任意一個字符開頭,以任意內容結尾的。
"-"可以指定範圍例如:[a-z]匹配a-z之間任意一個字符。
4.[^]或者 [!]
表示反向選擇 例如:[^Aa]* 表示匹配不以A或者a開頭的任意文件名。
5.{}
匹配其中一個指定的字符串,
例如:{string1,string2} 表示依次以string1、string2與單個文件名進行完整匹配。
二、引號
1.’'單引號
被單引號括起來的所有內容都是普通字符,就算特殊字符也不再有特殊含義。
2.""雙引號
由雙引號括起來的字符(除$、倒引號和轉義字符""以外)均是普通字符。
“$”:代表引用變量的值
“`”:倒引號代表引用命令
[root@localhost ~]# name=xiaopeng
[root@localhost ~]# echo '$name'
$name
[root@localhost ~]# echo "$name"
xiaopeng
三、輸入、輸出重定向符
表1-3-1 常用的輸入、輸出重定向
類型 | 符號 | 作用 |
---|---|---|
標準輸入重定向 | command <file | 將文件作爲命令的輸入 |
command <<分界符 | 從標準輸入中讀入,直到遇見分界符才停止 | |
標準輸出重定向 | command >file | 以覆蓋的方式,把command正確輸出結果輸出到file文件中 |
command >>file | 以追加的方式,把command正確輸出結果輸出到file文件中 | |
標準錯誤輸出重定向 | command 2>file | 以覆蓋的方式,把command的錯誤結果輸出到file文件中 |
command 2>>file | 以追加的方式,把command的錯誤結果輸出到file文件中 |
標準輸入stdin、標準輸出stdout和錯誤輸出stderr的文件描述符分別是0、1、2。(一般0和1可以不寫)
如果要把正確的結果和錯誤的結果都保存到一個文件裏,可以用 ls >file 2>&1
如果既不想把輸出結果保存到文件裏面也不想顯示在屏幕上,那麼可以把命令的所有結果重定向到 /dev/null,可以把/dev/null當成系統的垃圾箱,任何放入垃圾箱的數據都會被丟棄,無法恢復。
四、命令執行操作符
1.順序執行
使用";"連接多條命令,這些命令會依次執行,個命令之間沒有任何邏輯關係,就算有一條命令報錯後面也會繼續執行。它與寫成多行命令是等價的
2.邏輯與
如果使用"&&“連接多條命令,那麼這些命令之間就有了邏輯關係,只有第一條命令正確執行了,”&&"連接的第二條命令纔會執行。
3.邏輯或
使用"||"連接多條命令,則只有前一條命令執行錯誤,後一條命令纔會執行。
系統如何知道前一條命令是否執行呢? 那就需要用"$?"來查看前一條命令的返回值,如果是0則執行成功,如果是非0就執行錯誤。
五、小括號和大括號
小括號可以直接把若干命令括起來
大括號需要再{後面加一個空格,}前面加一個分號,大括號必須在結尾加上分號表示終止
小括號和大括號都可以將若干命令括起來(分號隔開),區別是:小括號執行組成命令時需要開啓一個子shell來執行,大括號直接在當前(父)shell中執行。
[root@localhost test]# cd
[root@localhost ~]# (cd /etc;pwd)
/etc
[root@localhost ~]# { cd /etc;pwd;}
/etc
[root@localhost etc]#
毋庸置疑:大括號執行以後父shell的路徑就到了etc
六、管道符、後臺命令符和註釋符
1.管道符"|"
用"|"表示,用來連接多條命令,前一條命令的輸出是後一條命令的輸入。只能處理前一條正確的輸出。
[root@localhost ~]# ls /etc |more
分頁顯示/etc目錄下的文件
2.後臺命令符"&"
當執行一些時間較長無交互的命令或者編譯時,可以在命令最後加上"&"。還可以把輸出結果重定向帶一個文件。
3.註釋符"#"
shell腳本以#開頭表示單行註釋。
在shell腳本中第一行以#!開頭後面跟shell的路徑,從而調用相應的解釋器。例如: #! /bin/bash
二、shell編程
一、變量
1.用戶自定義變量
變量名:系統變量用大寫字母,自定義變量用小寫字母(字母、下劃線開頭,由字母、數字和下劃線組成)
[root@localhost ~]# name=xiaopeng
[root@localhost ~]# echo "$name"
xiaopeng
變量賦值用"="
變量引用:變量名前面加上"$",
數組:用括號表示數組,數組裏面的值用空格分隔、
[root@localhost ~]# arr=(zhangsan lisi wangwi)
數組也可以arr[0]=zhangsan賦值
讀取數組:格式 “${數組名[下標]}”
[root@localhost ~]# echo "${arr[0]}"
zhangsan
2.系統預定義變量
表2-1-1 常用的預定義變量
預定義變量 | 作用 |
---|---|
$? | 上一個命令執行後的返回值(0是執行正確,非0是執行出現錯誤) |
$$ | 當前進程的進程號(pid) |
$! | 上一個後臺命令對應的進程號(pid) |
$- | 當前在運行shell程序的選項 |
$# | 命令行上參數的個數 |
$*,$@ | 命令行上實際給出的參數($*是個整體。$@是個迭代器類似數組,可以一個一個拿到) |
$n | n爲數字,$0是命令本身,$$1- 9 代 表 第 1 − 9 個 位 置 上 的 參 數 , 10 以 上 的 參 數 需 要 用 9代表第1-9個位置上的參數,10以上的參數需要用 9代表第1−9個位置上的參數,10以上的參數需要用${10} |
位置參數除了運行時傳遞參數外,還可以利用set命令賦值
shift命令可以把參數往左移一位,注意不能移走$0(命令本身)。
[root@localhost test]# cat sh0
#! /bin/bash
set agr1 arg2
echo "$1"
shift
echo "$1"
#注意兩次都是打印的$1,但是結果會不同,原因是因爲shift移動了參數。
[root@localhost test]# ./sh0
agr1
arg2
3.環境變量
環境變量是系統變量(永久生效需要寫入相應的配置文件),在當前shell和所有子shell中都生效。
使用env或者export可以查看已經定義的所有環境變量
HOME:用戶家目錄的絕對路徑
PATH:shell查找命令的列表。決定了shell將到那些目錄中尋找命令或者可執行程序,當用戶輸入命令或可執行程序時,Linux在這些目錄下按順序依次搜尋。
PS1:shell的主提示符
PWD:當前工作目錄的絕對路徑
SHELL:當前使用的shell
[root@localhost ~]# echo $HOME
/root
[root@localhost ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/usr/local/python3/bin:/root/bin
[root@localhost ~]# echo $PS1
[\u@\h \W]\$
[root@localhost ~]# echo $PWD
/root
[root@localhost ~]# echo $SHELL
/bin/bash
export聲明變量可以被子進程繼承,用法如下:
[root@localhost ~]# name=xiaopeng
[root@localhost ~]# export name
[root@localhost ~]# bash
[root@localhost ~]# echo "$name"
xiaopeng
變量的刪除: unset 變量名
[root@localhost ~]# unset name
[root@localhost ~]# echo "$name"
[root@localhost ~]#
4.數值運算
1.使用declare聲明變量
[root@localhost ~]# declare [選項] 變量名
選項:
-:給變量設定類型屬性
+:取消變量的類型屬性
-a:將變量聲明爲數組型
-i:將變量聲明爲整數型
-r:將變量聲明爲只讀變量 (不能用+r取消,也不能修改變量)
-x:將變量聲明爲環境變量
-p:顯示變量被聲明的類型
2.使用let命令和expr命令
[root@localhost ~]# a=1
[root@localhost ~]# b=1
[root@localhost ~]# let c=$a+$b
[root@localhost ~]# echo $c
2
-----expr----運算符左右必須有空格
[root@localhost ~]# aa=1
[root@localhost ~]# bb=2
[root@localhost ~]# cc=$(expr $aa + $bb)
[root@localhost ~]# echo $cc
3
3.使用"$((算術表達式))" 加上$符號才能返回值
[root@localhost ~]# aaa=1
[root@localhost ~]# bbb=1
[root@localhost ~]# ccc=$(($aaa+$bbb))
[root@localhost ~]# echo $ccc
2
表2-1-2 常用的算術運算符
優先級 | 算術運算符 | 作用 |
---|---|---|
1 | =、+=、-=、*=、/=、%=、&=、|=、>>=、<<= | 賦值、運算且賦值 |
2 | || | 邏輯或 |
3 | && | 邏輯與 |
4 | | | 按位或 |
5 | ^ | 按位異或 |
6 | & | 按位與 |
7 | ==、!= | 等於、不等於 |
8 | <=、>=、<、> | 小於等於、大於等於、小於、大於 |
9 | <<、>> | 按位左移、按位右移 |
10 | +、- | 加、減 |
11 | *、/、% | 乘、除、取模 |
12 | !、~ | 邏輯非、按位取反或補碼 |
13 | -、+ | 單目負、單目正 |
二、控制結構
1.條件測試:
條件測試有兩種形式:一種是用test命令;另一種是將一對方括號(方括號裏面頭尾加括號)將測試條件括起來。
test condition 等價於 [condition]
表2-2-1 文件測試運算符的形式及功能
參數 | 作用 |
---|---|
-r | 若文件存在且用戶可讀,測試條件爲真 |
-w | 若文件存在且用戶可寫,測試條件爲真 |
-x | 若文件存在且用戶可執行,測試條件爲真 |
-f | 若文件存在且是普通文件,測試條件爲真 |
-d | 若文件存在且是目錄文件,測試條件爲真 |
-b | 若文件存在且是塊設備文件,測試條件爲真 |
-c | 若文件存在且是字符設備文件,測試條件爲真 |
-s | 若文件存在且文件長度大於0,測試條件爲真 |
-e | 該文件是否存在 |
表2-2-2 字符串測試運算符的形式及功能
參數 | 作用 |
---|---|
-z s1 | 若字符串s1的長度爲0,則初始條件爲真 |
-n s1 | 若字符串s1的長度大於0,則測試條件爲真 |
s1 = s2 | 若s1=s2,測試條件爲真 |
s1 != s2 | 若s1不等於s2,測試條件爲真 |
表2-2-3 數值測試運算符的形式及功能
需要記幾個常用的英文單詞,就很容易了。
equal:平等的 greater than:大於 less then :小於
參數 | 作用 |
---|---|
n1 -eq n2 | 若n1等於n2,測試條件爲真 |
n1 -ne n2 | 若n1不等於n2,測試條件爲真 |
n1 -lt n2 | 若n1小於n2,測試條件爲真 |
n1 -le n2 | 若n1小於等於n2,測試條件爲真 |
n1 -gt n2 | 若n1大於n2,測試條件爲真 |
n1 -ge n2 | 若n1大於等於n2,測試條件爲真 |
2.if語句(判斷語句)
格式:
if [ 條件判斷式1 ]
then 命令1
elif [ 條件判斷式2 ]
then 命令2
else 命令3
fi
#! /bin/bash
echo -n "請輸入一個數字:(1-10):"
read a
if [ $a -lt 0 ] || [ $a -gt 10 ]
then echo "錯誤的數字,程序結束!"
exit 2
elif [ $a -lt 5 ]
then echo "$1 小於 5"
else echo "$1 is 大於等於 5"
fi
3.case語句(選擇語句)
格式:
case $變量名 in
“值1”) 命令;; #雙分號代表該段程序結束
“值2”) 命令;;
*) 命令;; #這裏的*號表示以上都不執行的時候執行它
esac
#! /bin/bash
echo -n "please input number:"
read a
case $a in
"1") echo "is one";;
"2") echo "is two";;
"3") echo "is three";;
"4") echo "is four";;
"5") echo "is five";;
*) echo "error";;
esac
4.while語句(循環語句)
格式:
while condition #條件成立執行
do
命令
done
eg:輸入一個數字來求1-這個數字的和
#! /bin/bash
echo -n "please input number:"
read a
i=1
sum=0
while [ $i -le $a ]
do
let sum+=i
let i++
done
echo "the sum is $sum"
5.until語句(循環語句)
格式:
until condition #條件不成立執行
do
命令
done
eg:求1-100的和
#! /bin/bash
sum=0
i=1
until ((i>100))
do
((sum+=i))
((i++))
done
echo "$sum"
6.for語句(循環語句)
語法1:
for((exp1;exp2;exp3))
do
命令
done
求1-100的和
#! /bin/bash
sum=0
for ((i=1;i<=100;i++))
do
((sum+=i))
done
echo "$sum"
7.for…in語句(循環語句)
for 臨時變量 in 取值列表
求1-6的和
sum1=0
for i in 1 2 3 4 5 6
do
((sum1+=i))
done
echo "$sum1"
8.select in語句(循環語句) 適合終端交互場景
select 臨時變量 in 取值列表
do
命令
done
通常和case in 一起用
#! /bin/bash
echo "Whit is your favourite OS:"
select name in "windows" "mac os" "linux" "unix" "android"
do
case $name in
"windows")
echo "windows是微軟發明的"
break;;
"mac os")
echo "mac是蘋果公司基於unix開發的一個圖形化界面操作系統"
break;;
“linux”)
echo "linux是類Unix操作系統,它開源免費"
break;;
"unix")
echo "unix是操作系統的開山鼻祖"
break;;
"android")
echo "android是谷歌公司開發的,基於Linux操作系統"
break;;
*)
echo "輸入錯誤,請重新輸入"
esac
done
9.continue和break
continue 用於跳出本層循環,後面跟數字表示跳出多少層
break 用於跳出整個循環,後面跟數字表示跳出多少個循環
三、shell函數
格式:
funtinue name() {
命令
[return 返回值可有可無]
}
調用:shell函數在定義時不能指明參數,但是在調用的時候可以傳遞參數,並且傳遞聲明參數它就接收什麼參數。不限制函數函數定義的位置,可以在前面調用也可以在後面調用。
#! /bin/bash
function test(){
echo $1
echo $2
echo $3
}
test 1 2 3 4
[root@localhost test]# ./function
1
2
3
腳本實例
模擬Linux登錄
#! /bin/bash
read -p "login:" name
read -p "password:" password
if [ "$name" = "zxp" -a "$password" = "123456" ]
then echo "welcome to linux"
else
echo "input is error"
fi
文件newusers給出了新用戶名單,爲新用戶創建賬號密碼。登錄名爲newusers文件裏面的名字,先檢查是否存在,若存在則提示"xx已經存在",若不存在則該創建用戶
[root@localhost test]# cat newusers
test1
test2
test1
test3
test5
test6
test7
test2
#! /bin/bash
read -p "please input the user password:" password
for i in `cat newusers`
do
id $i >/dev/null 2>&1
if [ $? -eq 0 ]
then echo "$i用戶已存在!"
else
useradd $i -p $password >/dev/null 2>&1
if [ $? -eq 0 ]
then echo "$i 創建成功"
else
echo "$i 創建失敗"
fi
fi
done