1.建立和運行shell程序
什么是shell程序呢? 簡單的說shell程序就是一個包含若干行
shell或者linux命令的文件.
象編寫高級語言的程序一樣,編寫一個shell程序需要一個文本編輯器.如VI等.
在文本編輯環境下,依據shell的語法規則,輸入一些shell/linux命令行,形成一個完整的程序文件.
執行shell程序文件有三種方法
(1)#chmod +x file
(2)#sh file
(3)# . file
在編寫shell時,第一行一定要指明系統需要那種shell解釋你的shell程序,如:#!/bin/bash
Unix/Linux上常見的Shell腳本解釋器有bash、sh、csh、ksh等,習慣上把它們稱作一種Shell。我們常說有多少種Shell,其實說的是Shell腳本解釋器。
- shell腳本的基本元素
#!<命令解釋器>
# --為注示
shell命令
流程控制(if/for/while/case/function)
- 為什么使用shell
解決重復操作的作業
節約時間,提高工作效率
功能強大
不需要編譯
- shell通配符
? 任意單個字符,不能匹配空
* 任意零個或多個字符組(不能匹配以點開頭的文件)
[ab] a或者b
[a-z] a到z之間的任意字符,包括端點在內
是Shell 而非命令本身處理通配符,命令后的通配符會在命令執行前就被代換了
如果需要命令而非Shell處理通配符,請用“\"將通配符轉義,跳脫字符
- bash中的引號
雙引號 “ ” :允許通過$符號引用其他變量值,會把引號的內容當成整體來看待
單引號 ‘ ’ :禁止引用其他變量值,shell中特殊符號都被視為普通字符,會把引號的內容當成整體來看待
反撇號 `` : 會把命令執行的結果輸出
$() 在執行命令的過程中會優先執行
; 連續執行命令
&& 可對一行命令進行分割,在執行過程中考慮上一個命令執行是否是正確的
|| 可對一行命令進行分割,在執行過程中不考慮上一個命令執行是否是正確的
! 命令歷史
# echo "This system is "HOSTNAME""
This is system is HOSTNAME
# echo "This system is "$HISTNAME""
This is system is
# echo "This system is "$HOSTNAME""
This is system is desktop8.example.com
# echo 'This system is "$HOSTNAME"'
This is system is "$HOSTNAME"
[root@desktop8 ~]# echo $5.00
5.00
[root@desktop8 ~]# echo \$5.00
$5.00
echo `ls`cat aaa.sh ``
# 將cmd1執行結果作為cmd2參數,再將cmd2結果作為cmd3的參數
echo $(cat $(ls))
cmd3 $(cmd2 $(cmd1))
echo `cat ddd`ls``
ls && cat ddd
lsa || cat ddd
運算符
$(()) :運算符
$[]
# a=$((1 + 10))
# echo $a
# a=$[1 + 100]
# echo $a
[root@vagrant-centos65 data]# aaa=$((10-1))
[root@vagrant-centos65 data]# echo $aaa
9
[root@vagrant-centos65 data]# aaa=$((10*1))
[root@vagrant-centos65 data]# echo $aaa
10
[root@vagrant-centos65 data]# aaa=$((9/3))
[root@vagrant-centos65 data]# echo $aaa
3
[root@vagrant-centos65 data]# aaa=$((9%3))
[root@vagrant-centos65 data]# echo $aaa
0
[root@vagrant-centos65 data]# aaa=$((9**3))
[root@vagrant-centos65 data]# echo $aaa
729
- shell的配置文件(軟件+配置文件)
用戶加載shell配置流程:
user01-->login-->bash-->/etc/profile-->$HOME/.bash_profile-->$HOME/.bashrc-->/etc/bashrc
全局配置文件
/etc/profile --bash工作環境的配置(環境變量)
export i=11
/etc/profile.d/*.sh --/etc/profile的擴展配置文件
/etc/bashrc --bash的配置文件
針對每個用戶的配置文件:
$HOME/.bash_history --存放命令歷史
$HOME/.bash_logout --注銷/退出shell的時候執行的腳本
$HOME/.bash_profile
$HOME/.bashrc
- 常用的幾個命令
ctrl + u --刪除當前光標至行首內容
ctrl + c --中斷
ctrl + l --清屏
ctrl + a --跳到行首 HOME
crtl + e --路到行尾 END
ctrl + r --快速搜索history命令
ctrl + z --轉入后臺運行 fg bg
Ctrl + d --退出shell,logout
↑(Ctrl+p) 顯示上一條命令
↓(Ctrl+n) 顯示下一條命令
- alias --查詢系統中所有已經存在的別名
alias 別名=‘真名’
unalias --取消系統中的別名
unalias 別名
unalias -a 刪除所有的別名
臨時: alias la='ls -a'
固定:
可以寫至以下文件,定義完成需要使用source來刷新,或者注銷重新登錄用戶:
/etc/profile
$HOME/.bash_profile
$HOME/.bashrc
/etc/bashrc
/etc/profile.d/*.sh
- 歷史命令
history 查詢當前用戶用過的所有命令歷史(內存)
history -w 同步內存中的命令至硬盤($/HOME/.bash_history)
自動同步:exit/注銷
echo "" > $HOME/bash_history --清空命令歷史
調用命令歷史:
!101 通過編號
!! 調用最后一條命令歷史
!vim 調用離我最近一條以vim開頭的命令歷史
!$ 調用最后一條命令歷史中的參數
命令字 + [選項] + 參數
ls -l /
ctrl + r 查找命令歷史
- bash的特殊符號
標準輸入 0
標準正確輸出(屏幕) 1
錯誤輸出 (屏幕) 2
> --輸出覆蓋重定向
>> --輸出追加重定向
2> --錯誤覆蓋輸出重定向
2>> --錯誤追加輸出重定向
&> --輸出正確/錯誤重定向
&>> --RHEL6可以實現正確和錯誤追加重定向。
>> --- 2>&1 rhel5
# cat /root/a2.txt /root &> a.txt --將正確和錯誤一起覆蓋重定向至a.txt
cat /root/a2.txt /root >> a.txt 2>&1 --將正確和錯誤一起追加重定向至a.txt
[root@i ~]# ls /ttttt /etc/passwd- >1.txt 2>2.txt && &>3.txt
2.shell中的變量
(1)常用系統變量
# :保存程序命令行參數的數目
? :保存前一個命令的返回碼
0 :保存程序名
* :以(" 1 2...")的形式保存所有輸入的命令行參數 所有的參數會被當做一個字符串
@ :以(" 1"" 2"...)的形式保存所有輸入的命令行參數 所有的參數會以空格做分隔符單做一個字符串
(2)定義變量
shell語言是非類型的解釋型語言,不象用C++/JAVA語言編程時需要事先聲明變量.給一個變量賦值,實際上就是定義了變量.
在linux支持的所有shell中,都可以用賦值符號(=)為變量賦值.
如: abc=9
由于shell程序的變量是無類型的,所以用戶可以使用同一個變量時而存放字符時而存放整數. 如:name=abc (bash/pdksh)
在變量賦值之后,只需在變量前面加一個 去引用.
echo $abc
刪除變量:
unset abc
(3)位置變量
當運行一個支持多個命令行參數的shell程序時,這些變量的值將分別存放在位置變量里. 其中第一個參數存放在位置變量1,第二個參數存放在位置變量2,依次類推...,shell保留這些變量,不允許用戶以令外的方式定義他們.同別的變量,用 符號引用他們.
總結:
- 變量的設置
- 變量的引用
- 刪除變量
(4)內置bash中變量
$#:命令行中位置變量的個數
$*:所有位置變量的內容
$@: 所有位置參數的內容,與$*的分割任不一樣,建議和所有的位置參數時使用這種方式。
$?:上一條命令執行后返回的狀態,當返回狀態值為0時表示執行正常,非0值表示執行異?;虺鲥e
$$:當前所在進程的進程號
$!:后臺運行的最后一個進程號
$0:當前執行的進程/程序名
3.shell中引號的使用方法
shell使用引號(單引號/雙引號)和反斜線("")用于向shell解釋器屏蔽一些特殊字符. 反引號(")對shell則有特殊意義.
如: abc="how are you" (bash/pdksh)
這個命令行把三個單詞組成的字符串how are you作為一個整體賦值給變量abc.
abc1='$LOGNAME,how are you!' (bash/pdksh)
abc2="$LOGNAME,how are you!" (bash/pdksh)
LOGNAME變量是保存當前用戶名的shell變量,假設他的當前值是:wang.執行完兩條命令后, abc1的內容是LOGNAME, how are you!.而abc2的內容是;wang, how are you!.
象單引號一樣,反斜線也能屏蔽所有特殊字符.但是他一次只能屏蔽一個字符.而不能屏蔽 一組字符.
反引號的功能不同于以上的三種符號.他不具有屏蔽特殊字符的功能.但是可以通過他將一個命令的運行結果傳遞給另外一個命令.
如:
contents=ls
(bash/pdksh)
4.shell程序中的test命令
- 算術操作(expr)
在bash中只能做整數的運算
+ 加
- 減
* 乘
/ 除(取整)
% 取余
$(())
$[]
[root@vagrant-centos65 data]# aa=$((10-1))
[root@vagrant-centos65 data]# echo $aa
9
[root@vagrant-centos65 data]# bb=$[10/10]
[root@vagrant-centos65 data]# echo $bb
1
[root@vagrant-centos65 data]# cc=$[10+10]
[root@vagrant-centos65 data]# echo $cc
20
- 退出狀態
在Linux系統中,每當命令執行完成后,系統都會返回一個退出狀態。該退出狀態用一整數值表示,用于判斷命令運行正確與否。
若退出狀態值為0,表示命令運行成功
若退出狀態值不為0時,則表示命令運行失敗
最后一次執行的命令的退出狀態值被保存在內置變量“$?”中,所以可以通過echo語句進行測試命令是否運行成功
0 表示運行成功,程序執行未遇到任何問題
1~125 表示運行失敗,腳本命令、系統命令錯誤或參數傳遞錯誤
126 找到了該命令但無法執行
>128 命令被系統強制結束
test命令
用途:測試特定的表達式是否成立,當條件成立時,命令執行后的返回值$?為0,否則為其他數值
格式: test 條件表達式
[ 條件表達式 ]
test可以測試表示有哪些:
1、文件狀態
2、字符串的比對
3、整數的比對
4、多條件組合(|| && !)(-a -o !)
#man test
-a = && -o = || !
單個條件: [ ! 1 -eq 1 ] 兩個值的結果再取反 ,感嘆號的優先級別最低,除非加括號;
! [ 1 -eq 1 ]
多個條件:
[ 1 -eq 1 -a 10 -eq 10 ] = [ 1 -eq 1 ] && [ 10 -eq 10 ] 兩個條件成立,才正確;
[ 1 -eq 1 -o 10 -eq 10 ] = [ 1 -eq 1 ] || [ 10 -eq 10 ] 取或;
[ 1 -eq 1 -o 10 -eq 10 -o 1 -eq 1 ] = [ 1 -eq 1 ] || [ 10 -eq 10 ] || [ 1 -eq 1 ]
-----------------------------------------------------
# test 1 = 1
# echo $?
0
# [ 1 = 1 ] --[] = test --單條件
# echo $?
0
# [ 1 = 1 ] && echo YES
YES
# [ 1 = 2 ] && echo YES --無返回
|| -o or
&& -a and
!
條件的組合:
[ 1 = 1 -a 1 = 2 ] 與組合
[ 1 = 1 ] && [ 1 = 2 ] 與組合
[ 1 = 1 ] || [ 1 = 2 ] 或組合
[ 1 = 1 -o 1 = 2 ] 或組合
在bash中,命令test用于計算一個條件表達式的值.他們經常在條件語句和循環語句中被用來判斷某些條件是否滿足.
test命令的語法格式:
test expression
或者
[expression]
- 邏輯運算符
邏輯運算符主要包括邏輯非、邏輯與、邏輯或運算符,具體描述如下表所示:
邏輯操作符 描述
!expression 如果expression為假,則測試結果為真
expression1 a expression2 如果expression1和expression同時為真,則測試結果為真
expression1 o expression2 如果expression1和expression2中有一個為真,則測試條件為真
在test命令中,可以使用很多shell的內部操作符.這些操作符介紹如下:
(1)字符串操作符 用于計算字符串表達式
test命令 | 含義
Str1 = str2 | 當str1與str2相同時,返回True
Str1! = str2| 當str1與str2不同時,返回True
Str | 當str不是空字符時,返回True
-n str | 當str的長度大于0時,返回True
-z str | 當str的長度是0時,返回True
(2)整數操作符具有和字符操作符類似的功能.只是他們的操作是針對整數
test表達式 | 含義
Int1 -eq int2|當int1等于int2時,返回True
Int1 -ge int2|當int1大于/等于int2時,返回True
Int1 -le int2|當int1小于/等于int2時,返回True
Int1 -gt int2|當int1大于int2時,返回True
Int1 -ne int2|當int1不等于int2時,返回True
(3)用于文件操作的操作符,他們能檢查:文件是否存在,文件類型等
test表達式 | 含義
-d file |當file是一個目錄時,返回 True
-f file |當file是一個普通文件時,返回 True
-r file |當file是一個刻讀文件時,返回 True
-s file |當file文件長度大于0時,返回 True
-w file |當file是一個可寫文件時,返回 True
-x file |當file是一個可執行文件時,返回 True
(4)shell的邏輯操作符用于修飾/連接包含整數,字符串,文件操作符的表達式
test表達式 | 含義
! expr |當expr的值是False時,返回True
Expr1 -a expr2|當expr1,expr2值同為True時,返回True
Expr1 -o expr2|當expr1,expr2的值至少有一個為True時,返回True
5.條件語句
同其他高級語言程序一樣,復雜的shell程序中經常使用到分支和循環控制結構,
bash,pdksh分別都有兩種不同形式的條件語句:if語句和case語句.
(1)if語句
語法格式:
bash/pdksh用法:
if [expression1]
then
commands1
elif [expression2]
commands2
else
commands3
if
含義:當expression1的條件為True時,shell執行then后面的commands1命令;當
expression1的條件為false并且expression2的條件滿足為True時,shell執行
commands2命令;當expression1和expressin2的條件值同為false時,shell執行
commands3命令.if語句以他的反寫fi結尾.
(2)case語句
case語句要求shell將一個字符串S與一組字符串模式P1,P2,...,Pn比較,當S與
某個模式Pi想匹配時,就執行相應的那一部分程序/命令.shell的case語句中字符
模式里可以包含象*這樣的通配符.
語法格式:
bash/pdksh用法:
case string1 in
str1)
commands1;;
str2)
commands2;;
*)
commands3;;
esac
含義:shell將字符串string1分別和字符串模式str1和str2比較.如果string1與str1匹配,則shell執行commands1的命令/語句;如果string11和str2匹配,則shell執行commands2的命令/語句.否則shell將執行commands3的那段程序/命令.其中,每個分支的程序/命令都要以兩個分號(;;)結束.
6.循環語句
當需要重復的某些操作時,就要用到循環語句
(1)for語句
大家知道在很多編程語言中for語句是最常見.在shell中也不例外.for語句要求shell將包含
在這個語句中的一組命令連續執行一定的次數.
語法格式:
bash/pdksh
用法1:
for var1 in list
do
commands
done
含義:在這個for語句中,對應于list中的每個值,shell將執行一次commands代表的一組命令.
在整個循環的每一次執行中,變量var1將依此取list中的不同的值.
用法2:
for var1
do
setatements
done
含義:在這個for語句中,shell針對變量var1中的每一項分別執行一次statements代表的一組
命令.當使用這種形式的語句時,shell認為var1變量中包含了所有的位置變量,而位置變量中
存放著程序的命令行參數值.也就是說,他等價于下列形式:
for var1 in " @"
do
statements
done
舉例:
for file ;bash/pdksh
do
tr a-z A-Z< file>file.caps
done
(2)while語句
while語句是shell提供的另一種循環語句. while語句指定一個表達式和一組命令.這個語句使得shell重復執行一組命令,直到表達式的值為False為止.
語法格式:
while expression ;bash
do
statements
done
舉例:
#!/bin/bash
count=1
while true
do
echo "this is a parameter number $count $1"
shift
count=$[ $count+1 ]
done
語句中shift命令的功能是將所有的命令行參數依次相左傳遞.
7.shell中的函數
1、在編寫Shell腳本程序時,將一些需要重復使用的命令操作,定義為公共使用的語句塊,即可稱為函數
2、合理使用Shell函數,可以使腳本內容更加簡潔,增強程序的易讀性,提高執行效率
shell允許用戶定義自己的函數.函數是高級語言中的重要結構.shell中的函數于C或
者其他 語言中定義的函數一樣.與從頭開始,一行一行地寫程序相比,使用函數主要好處是有 利于組織 整個程序.在bash中,一個函數的語法格式如下:
fname (){
shell comands
}
定義好函數后,需要在程序中調用他們.bash中調用函數的格式:
fname [parm1 parm2 parm3...]
調用函數時,可以向函數傳遞任意多個參數.函數將這些參數看做是存放他的命令行參數的 位置變量
總結
利用shell編程是提高系統管理工作效率的重要手段,學好shell跟了解系統基本命令
和管理工具的使用方法同樣重要!
附:
A.bash中常用的命令
命令 | 含義
& 把程序放到后臺執行
ctrl + z 可以將一個正在前臺執行的命令放到后臺,并且暫停
Alias |設置命令別名
Bg |將一個被掛起的進程在后臺執行
cd |改變用戶的當前目錄
exit |終止一個shell
export |使作為這個命令的參數的變量及其當前值,在當前運行的shell的子進程中可見
fc |編輯當前的命令行歷史列表
fg |讓一個被掛起的進程在前臺執行
help |顯示bash內部命令的幫助信息
history |顯示最近輸入的一定數量的命令行
kill |終止一個進程
pwd |顯示用戶當前工作目錄
unalias |刪除命令行別名
B.bash中常用的系統變量
變量 | 含義
EDITOR,FCEDIT |Bash的fc命令的默認文本編輯器
HISTFILE |規定存放最近輸入命令行文件的名字
HISTSIZE |規定命令行歷史文件的大小
HOME |當前用戶的宿主目錄
OLDPWD |用戶使用的前一個目錄
PATH |規定bash尋找可執行文件時搜索的路徑
PS1 |命令行環境中顯示第一級提示符號
PS2 |命令行環境中顯示第二級提示符號
PWD |用戶當前工作目錄
SECONDS |當前運行的bash進程的運行時間(以秒為單位)一
排序統計相關的:wc sort uniq
wc
-l 顯示行數
-w 顯示單詞數
-m 顯示字符數
默認不加參數,就是相當于上面三個參數都加
[root@li shell01]# cat /etc/passwd |wc -l
79
[root@li shell01]# cat /etc/passwd |wc -w
106
[root@li shell01]# cat /etc/passwd |wc -m
3374
[root@li shell01]# cat /etc/passwd |wc
79 106 3374
wc -L 算一個文件里最長一行有多少個字符
sort 排序命令
[root@li shell01]# cat /etc/passwd |
sort --默認以開頭字母排序
-r 反向排序
-n 以數字來排
-f 大小寫不敏感
-t 分隔符
-k 接數字代表第幾列
cut [-bn] [file] 或 cut [-c] [file] 或 cut [-df] [file]
cut 命令從文件的每一行剪切字節、字符和字段并將這些字節、字符和字段寫至標準輸出。
如果不指定 File 參數,cut 命令將讀取標準輸入。必須指定 -b、-c 或 -f 標志之一。
-b :以字節為單位進行分割。這些字節位置將忽略多字節字符邊界,除非也指定了 -n 標志。
-c :以字符為單位進行分割。
-d :自定義分隔符,默認為制表符。
-f :與-d一起使用,指定顯示哪個區域。
-n :取消分割多字節字符。僅和 -b 標志一起使用。如果字符的最后一個字節落在由 -b 標志的 List 參數指示的<br />范圍之內,該字符將被寫出;否則,該字符將被排除。
[root@li ~]# cut -d -f
[root@li ~]# sort -t -k
[root@li ~]# awk -F n
[root@li shell01]# cat /etc/passwd |sort -t ":" -k 3 --以UID來排序,但是它只會以數字的第一個數字來排也就是說 2要排到14的后面
[root@li shell01]# cat /etc/passwd |sort -t ":" -k 3 -n --多加一個-n參數,才會以整個的數字大小來排序
uniq 唯一命令
默認是以連續的重復值內只取一個
[root@li shell01]# cat /etc/passwd |cut -d ":" -f7 |uniq |grep bash
/bin/bash
/bin/bash
/bin/bash
/bin/bash
[root@li shell01]# cat /etc/passwd |cut -d ":" -f7 |grep bash |uniq
/bin/bash
--在管道用得多的情況下,命令的順序會造成很大的結果不同
---------------------------------
練習:
對有下面內容的文件進行操作
http://a.domain.com/1.html
http://b.domain.com/1.html
http://c.domain.com/1.html
http://a.domain.com/2.html
http://a.domain.com/3.html
http://b.domain.com/3.html
http://c.domain.com/2.html
http://c.domain.com/3.html
http://a.domain.com/1.html
得到下面的結果
4 a.domain.com
3 c.domain.com
2 b.domain.com
cat 1.txt |cut -d"/" -f3 |sort|uniq -c |sort -n -r
- bash的調試方法
打開調試模式
? $set -x
? $bash -x shell.sh
? 關閉調試模式
? $set +x
sh -n test.sh --檢查語法(結構化語句的語法)
sh -x test.sh --調試
如果參數過太多,出現這個報錯:too many arguments,需要使用xargs
xargs (1) - build and execute command lines from standard input
# awk -F: '{print $1}' /etc/passwd | xargs -i mkdir -p {}