shell腳本

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保留這些變量,不允許用戶以令外的方式定義他們.同別的變量,用 符號引用他們.
總結:

  1. 變量的設置
  2. 變量的引用
  3. 刪除變量

(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 {}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容