Linux Shell 編程基礎詳解——吐血整理,牆裂推薦!

第一部分:Linux Shell 簡介

Shell 是一個用 C 語言編寫的程序,它是用戶使用 Linux 的橋樑。Shell 既是一種命令語言,又是一種程序設計語言。
Shell 是指一種應用程序,這個應用程序提供了一個界面,用戶經過這個界面訪問操做系統內核的服務。
Ken Thompson 的 sh 是第一種 Unix Shell,Windows Explorer 是一個典型的圖形界面 Shell。
當一個用戶登錄linux 系統後,系統就會爲該用戶建立一個shell程序。
Shell的版本:linux

  • Bourne Shell:是貝爾實驗室開發的,unix廣泛使用的shell,在編程方面比較優秀,但在用戶交互方面沒有其餘shell優秀。
  • BASH:是GNU的Bourne Again Shell,是GNU操做系統上默認的shell,在bourne shell基礎上加強了不少特性,如命令補全,命令歷史表等等
  • Korn Shell:是對Bourne Shell 的發展,在大部份內容上與Bourne Shell兼容,集成了C Shell和Bourne shell優勢。
  • C Shell:是SUN公司Shell的BSD版本,語法與c語言類似,比bourne shell 更適合編程

第二部分 Shell 程序設計基礎

2.1 Shell 輸入輸出

2.1.1 echo

echo命令能夠顯示文本行或變量取值,或者把字符串輸入到文件中
格式: echo string
echo的經常使用功能:\c 不換行 \f 不進紙 \t 跳格 \n 換行shell

note:
對於linux系統,必須使用-e選項來使以上轉義符生效編程

例:bash

$ echo  -e  "hello\tboy"
hello	boy

echo命令對特殊字符敏感,若是要輸出特殊字符,須要用\屏蔽其特殊含義。
經常使用的特殊字符:雙引號"" 反引號`` 反斜線\
例:app

$ echo "\"\""      //想輸出""
""

2.1.2 read

read命令從鍵盤或者文件的某一行文本中讀入信息,並將其賦給一個變量。
若是隻指定了一個變量,read會把全部的輸入賦給該變量,直至遇到第一個文件結束符或回車
格式: read var1 var2 …
例1:函數

chenshifengdeMacBook-Pro:~ chenshifeng$ read name
Hello I am superman
chenshifengdeMacBook-Pro:~ chenshifeng$ echo $name
Hello I am superman

若是輸入的值個數多於變量個數,多餘的值會賦給最後一個變量:
例2:oop

chenshifengdeMacBook-Pro:~ chenshifeng$ read name surname
John Mike Kate
chenshifengdeMacBook-Pro:~ chenshifeng$ echo $surname   
Mike Kate
chenshifengdeMacBook-Pro:~ chenshifeng$

2.1.3 cat

cat能夠用來顯示文件,而且支持將多個文件串鏈接後輸出測試

note:該命令一次顯示完整個文件,若想分頁查看,需使用moreui

格式: cat [ options ] filename1 … filename2 …
經常使用options:spa

  • -v 顯示控制字符
  • -n 對全部輸出行進行編號
  • -b 與-n類似,但空白行不編號

例:

$ cat  file1 file2 file3       // 同時顯示三個文件
$ cat –b file1 file2 file3

2.1.4 管道 |

能夠經過管道把一個命令的輸出傳遞給另一個命令作爲輸入
格式: 命令1 | 命令2
例:

$ cat test.txt | grep 'hello'

2.1.5 tee

把輸出的一個副本輸送到標準輸出,另外一個副本拷貝到相應的文件中
若是想看到輸出的同時,把輸出也同時拷入一個文件,這個命令很合適
格式: tee -a file

  • -a 表示文件追加到末尾
  • file 表示保存輸出信息的文件

tee命令通常和管道符|結合起來使用
例:

$ who | tee who.info      // 該命令的信息返回在屏幕上,同時保存在文件who.info中
$ who | tee who.info
chenshifeng console  Jan  9 12:56 
chenshifeng ttys000  Jan  9 13:27 
chenshifeng ttys004  Jan  9 19:11 
chenshifeng ttys005  Jan 10 00:12 
$ cat who.info 
chenshifeng console  Jan  9 12:56 
chenshifeng ttys000  Jan  9 13:27 
chenshifeng ttys004  Jan  9 19:11 
chenshifeng ttys005  Jan 10 00:12

2.1.6 標準輸入,輸出和錯誤

當咱們在shell中執行命令的時候,每一個進程都和三個打開的文件相聯繫,並使用文件描述符來引用這些文件,見下表

文件 文件描述符
輸入文件-標準輸入 0
輸出文件-標準輸出 1
錯誤輸出文件-標準錯誤 2

系統中實際上有12個描述符,能夠任意使用文件描述符3-9
標準輸入 對應文件描述符0,是命令的輸入,缺省鍵盤
標準輸出 對應文件描述符1,是命令的輸出,缺省屏幕或文件
標準錯誤 對應文件描述符2,是命令錯誤的輸出,缺省屏幕或文件
利用文件重定向功能對命令的標準輸入,輸出和錯誤進行修改。
經常使用文件重定向命令:

command > file:                   標準輸出重定向到一個文件,錯誤仍然輸出屏幕
command >> file:                  標準輸出重定向到一個文件(追加)
command 1> file:                  標準輸出重定向到一個文件
command 2> >file:                 標準錯誤重定向到一個文件(追加) 
command >file 2>&1:               標準輸出和標準錯誤一塊兒重定向到一個文件
command >>file 2>&1:              標準輸出和標準錯誤一塊兒重定向到一個文件(追加)
command < file1 >file2:           以file1作爲標準輸入,file2作爲標準輸出
command <file:                    以file作爲文件標準輸入  

結合使用標準輸出和標準錯誤

$ cat hello 1>myfile.out  2>myerror.out

合併標準輸出和標準錯誤

$ cat >>mylog.out  2>&1  <hello

2.2 Shell 後臺執行命令

2.21 cron

cron是系統的調度進程,可在無人干預的狀況下運行做業,經過crontab的命令容許用戶提交,編輯或者刪除相應的做業。
每一個用戶均可以有一個crontab文件來保存調度信息,經過該命令運行任意一個shell腳本或者命令
在大的系統中,系統管理員能夠經過cron.deny和cron.allow這兩個文件來禁止或容許用戶擁有本身的crontab文件

crontab的域
第1列 分鐘0~59
第2列 小時0~23(0表示子夜)
第3列 日1~31
第4列 月1~12
第5列 星期0~6(0表示星期天)
第6列 要運行的命令

crontab格式: 分<>時<>日<>月<>星期<>要運行的命令
<>表示空格

note:若是要表示範圍的話,如週一到週五,能夠用1-5表示
若是要列舉某些值,如周1、週五,能夠用1,5表示

例1:

30  21  *  *  *  /apps/bin/cleanup.sh

例2:

0,30  18-23  *  *  *  /apps/bin/dbcheck.sh

crontab的命令選項
格式:crontab [ -u user ] -e -l -r
其中

  • -u 用戶名,若是使用本身的名字登錄,就不用使用-u選項
  • -e 編輯crontab文件
  • -l 列出crontab文件中的內容
  • -r 刪除crontab文件

建立一個新的crontab文件

1 建立一個文件,建議名爲 cron,例shifengcron,在文件中假如以下內容:

0,10,20,30,40,50  *  *  *  *  /bin/echo "hello boy"

保存退出
2 提交剛剛建立的cron文件shifengcron

$ crontab shifengcron
$ ls /var/spool/cron/ 是否生成文件shifengcron

列出crontab文件

$ crontab –l
$ crontab –l  >  $HOME/mycron   能夠經過這種方法對crontab進行備份

編輯crontab文件

$ crontab  -e

修改後保存退出,cron會對其進行必要的完整性檢查

刪除crontab文件

$ crontab –r

crontab文件的恢復

若是誤刪了crontab文件,假設在$HOME目錄下還有備份,能夠將這個備份文件拷貝到/var/spool/cron/ username是用戶名,若是因爲權限問題沒法拷貝,可使用

$ crontab <filename>

note:filename是備份的crontab文件的名字

2.22 at

at命令容許用戶向cron守護進程提交做業,使其在稍後的時間運行,這個時間能夠是10min之後,也多是幾天之後,但若是時間比較長,建議仍是使用crontab
格式:at [ -f script ] [ -m -l -r ] [ time ] [ date ]

  • -f script 是要提交的腳本或命令
  • -m 做業完成後給用戶發郵件
  • -r 清除某個做業,須要提供做業標識id
  • time 做業執行的時間格式能夠爲:HH. MM ,HH:MM
  • H表明小時,M表明分鐘
  • date 日期格式能夠是月份數或日期數,並且at命令能夠識別諸如today,tomorrow這樣的詞

能夠經過命令行方式或者at命令提示符方式來提交做業,通常來說,若是提交多個命令,可使用at命令提示符;若是提交的是shell腳本,可使用命令行方式
例:提示符方式:

$ at 01:15
at > echo 「hello」
at > echo 「boy」  >/home/wuxh/at.log
at > <EOT>

note:EOT是Ctrl+D,任務執行後,會給當前用戶發送郵件,經過mail命令能夠查看相關信息,也能夠將信息重定向到文件

例:提交shell腳本方式

$ at  3:00pm  tomorrow –f   /home/wuxh/hello.sh

note:該腳本將在明天下午3點運行,使用腳本方式,要加參數-f

列出at任務,格式:at -l
例:

$ at  -l  
5	2021-01-17	11:20	a	root

note: 第一個是做業標識id;第二個是日期;第三個是時間;a表明at;第四個表明建立任務的用戶
清除at任務
格式:at -r

$ at  –r  [ job no]

例:$ at -r 5

note:不接job no將清除全部未執行的任務,接具體job id將清楚對應的任務

2.23 &

當在前臺運行某個做業時,終端被該做業佔據;而當它在後臺運行時,它不會佔據終端
能夠藉助&命令把做業放到後臺執行
格式: 命令 &

注:
1 .須要用戶交互的命令不要放在後臺執行,不然機器一直等待
2 .後臺程序在執行時,執行結果仍然會輸出到屏幕,干擾咱們的工做,建議將這樣的信息重定向到某個文件
即:command > out.file 2>&1 &
將標準輸入錯誤輸出都定向到一個out.file的文件中
例:$ find /etc/ -name "hello" -print >find.dt 2>&1 &

2.3 引號

"" 雙引號
` 反引號
'' 單引號
\ 反斜線

2.31 雙引號

可引用除字符$,`,\外的任意字符或者字符串,對$,`,\敏感

例1:

$ echo "hello"
hello

例2:

$ echo "$$"
8311            ///想輸出字符$$  結果看到的是數值8311 
$ echo "\$$"       //對特殊字符須要反斜線屏蔽其特殊含義
$$               //獲得想要的結果

例3:

$ echo "`V_V`"  //想輸出`V_V`字樣    結果獲得錯誤信息
$ echo "\`V_V\`"    //獲得`V_V`輸出

2.32 單引號

單引號和雙引號的用法基本相似,不一樣的是單引號對特殊字符不敏感,能夠將其作爲普通字符輸出出來
例:

$ echo '$$'               //結果 $$  不用藉助\進行屏蔽
$ echo '`V_V`'          //結果`V_V`,和前頁雙引號比較

2.33 反引號

該命令用於設置系統命令的輸出到變量,shell將反引號中的內容作爲命令執行。
例1:

$ echo `hello`
-bash: hello: command not found

例2:

$ echo `date`
2021年 1月17日 星期日 23時40分18秒 CST

反引號能夠和雙引號結合起來使用:
例3:

$ echo "The date today is `date`"
The date today is 2021年 1月17日 星期日 23時41分15秒 CST

2.34 反斜線

若是一個字符有特殊含義,爲防止shell誤解其含義,可用\屏蔽該字符
具備特殊含義的字符
------------------------------------------------------------------------------------
& * ^ $ ` 「 |
------------------------------------------------------------------------------------
例1 :

$ echo "$$"           //在屏幕上輸出$$字符,結果顯示3853
$ echo "\$$"          //用反斜線屏蔽,防止shell誤解,結果顯示$$

例2:

$ echo  *         //在屏幕上輸出*字符,結果輸出當前目錄下內容
$ echo  \*            //用反斜線屏蔽,防止shell誤解,輸出*字符

2.4 Shell變量,參數

2.4.1 系統變量

系統變量適用於全部用戶進程,能夠在命令行中設置,但用戶註銷時這些值將丟失,最好在.profile中進行定義,或者/etc/profile
傳統上,全部環境變量都大寫,且必須用export命令導出
設置環境變量:

var_name=value; export var_name

或者:

var_name=value
export var_name

又或者

export var_name=value

查看環境變量:

echo $var_name
  • env 該命令可查看全部系統環境變量
  • unset var_name 清除系統環境變量

嵌入shell變量
通常來說,bourne shell有一些預留的環境變量名,這些變量名不能作其餘用途,一般在/etc/profile中創建這些嵌入的環境變量,但這不絕對,取決於用戶
shell的變量列表:
CDPATH; EXINIT; HOME; IFS; LOGNAME; MAIL;MAILCHECK; PATH; PS1; PS2; SHELL; TERMINFO;TERM; TZ

2.4.2 用戶變量

在用戶shell生命週期的腳本中使用,不一樣的用戶能夠定義各自的用戶變量 ~/.bashrc
用法:

var_name=value

顯示變量:

echo $var_name
or  echo ${var_name}   //建議使用

清除變量:

unset var_name

顯示用戶全部變量:set
測試變量是否設置:echo ${var:=value} 若未設置或未初始化,可用新值

使用變量保存系統命令參數
例:

$ SOURCE="/etc/passwd"
$ DEST="/home/chenshifeng/
$ cp $SOURCE $DEST

設置只讀變量
可設置某個變量爲只讀方式,只讀變量不可更改,不然系統返回錯誤
用法:

var_name=value
readonly var_name

例:

$ myvar="100"
$ readonly myvar
$ myvar="200"        
$ -bash: myvar: readonly variable

2.4.3 位置變量

位置變量屬於只讀變量
做用:向shell腳本傳遞參數,參數個數能夠任意多,但只有前9個被訪問到,shift命令能夠更改這個限制。
每一個訪問參數前加$,
第一個參數爲0,表示預留保存實際腳本名字,不管腳本是否有參數,此值都可用,如:給腳本test傳遞信息:
Would you like to do it

$0 $1 $2 $3 $4 $5 $6 $7 $8 $9
腳本名字 would you like to do it

例:$ vi test

#!/bin/sh
echo "The full name is : $0 "
echo "The script name is : `basename $0`"
echo "The first parameter is :$1"
echo "The second parameter is :$2"
echo "The third parameter is :$3"
echo "The fourth parameter is :$4"
echo "The fifth parameter is :$5"
echo "The sixth parameter is :$6"
echo "The seventh parameter is :$7"
echo "The eighth parameter is :$8"
echo "The ninth parameter is :$9"

保存文件,執行 $ ./test would you like to do it

The full name is : ./test 
The script name is : test
The first parameter is :would
The second parameter is :you
The third parameter is :like
The fourth parameter is :to
The fifth parameter is :do
The sixth parameter is :it
The seventh parameter is :
The eighth parameter is :
The ninth parameter is :

note:上例中$0返回的信息中包含路徑名,若是隻想獲得腳本名稱,能夠藉助basename,將腳本中第一句修改成:
echo "The script name is : \`basename \$0\` "
保存文件,執行 ./test would you like to do it

note:basename 用``向系統命令傳遞參數

能夠在腳本中向系統命令傳遞參數

$ vi findfile
#!/bin/sh
find / -name  $1

保存,執行

$ ./findfile  passwd

2.4.4 特定變量

特定變量屬於只讀變量,反映腳本運行過程當中的控制信息
特定的shell變量列表:

變量 說明
$# 傳遞到腳本的參數個數(經常使用)
$* 以一個單字符串的形式顯示全部向腳本傳遞的參數,與位置變量 不一樣,此項參數可超過9個
$$ 腳本運行的當前進程id號(經常使用)
$! 後臺運行的最後一個進程的進程id號
$@ 與$*相同,可是使用時加引號,並在引號中返回每一個參數
$- 顯示shell使用的當前變量,與set命令功能相同
$? 顯示最後命令的退出狀態,0表示正確,其餘任何值表示錯誤(經常使用)

例:修改test腳本,追加特定變量信息:

#!/bin/sh
echo "The full name is : $0 "
echo "The script name is : `basename $0`"
echo "The first parameter is :$1"
echo "The second parameter is :$2"
echo "The third parameter is :$3"
echo "The fourth parameter is :$4"
echo "The fifth parameter is :$5"
echo "The sixth parameter is :$6"
echo "The seventh parameter is :$7"
echo "The eighth parameter is :$8"
echo "The ninth parameter is :$9"

echo "The number of arguments passed :$#"
echo "Show all arguments :$*"
echo "Show my process id :$$"
echo "Show me the arguments in quotes :$@"
echo "Did my script go with any errors :$?"

最後的退出狀態 $?
能夠在任何腳本或者命令中返回此變量以得到返回信息,基於此信息,能夠在腳本中作更進一步的研究,返回0爲成功,1爲失敗
例1:

$ cp /etc/passwd /home/chenshifeng/myfile
$ echo $?
0

例2:

$ cp /etc/passwd /home/wuxh/mydir   //<mydir不存在>
$ echo $?
1

建議將返回值設置爲一個有意義的名字,增長腳本的可讀性
修改例2

$ cp_status=$?
$ echo $cp_status

第三部分 Shell程序設計流程控制

3.1 Test 測試命令

3.1.1 文件測試

測試文件狀態:
用法:test condition 或者 [ condition ]
文件狀態列表

  • -d 目錄
  • -s 文件長度大於0,非空
  • -f 正規文件
  • -w 文件可寫
  • -L 符號文件
  • -u 文件有uid設置
  • -r 文件可讀
  • -x 文件可執行

例:

$ ls  -l  hello
$ [  -w hello  ]    
$ echo $?

使用邏輯操做符:
測試文件狀態是否ok,能夠藉助邏輯操做符對多個文件狀態進行比較

  • -a 邏輯與,操做符兩邊均爲真,結果爲真,不然爲假
  • -o 邏輯或,操做符兩邊一邊爲真,結果爲真,不然爲假
  • ! 邏輯否,條件爲假,結果爲真

例1:

$ [  -r myfile1    -a   -w  myfile2   ] 
$ echo $?

例2:

$ [  -w myfile1    -o   -x  myfile2   ] 
$ echo $?

3.1.2 字符串測試

字符串測試是錯誤捕獲很重要的一部分,特別是用戶輸入或比較變量時尤其重要
格式:

  • test "string"
  • test string_operator "string"
  • test "string" string_operator "string"
  • [ string_operator string ]
  • [ string string_operator string ]

注:string_operator 的取值:
= 等於 != 不等於 -z 空串 -n 非空串

例:測試變量string1是否等於string2

$ string1="hello"
$ string2="Hello"
$ [  "$string1" = "$string2"  ]
$ echo $?

note:在進行字符串比較時,必定要加引號;等號先後要加空格。

3.1.3 數值測試

格式:"number" number_operator "number"
或者:[ "number" number_operator "number" ]
number_operator 的取值範圍:

比較符 說明
-eq 數值相等
-gt 第一個數大於第二個數
-ne 數值不相等
-lt 第一個數小於第二個數
-le 第一個數小於等於第二個數
-ge 第一個數大於等於第二個數

例1:

[root@chenshifengdeLinuxServer ~]# NUM1=130
[root@chenshifengdeLinuxServer ~]# [ "$NUM1" -eq  "130" ]
[root@chenshifengdeLinuxServer ~]# echo $?
0

例2:

[root@chenshifengdeLinuxServer ~]# [ "990" -le "996" -a "123" -gt "33" ]
[root@chenshifengdeLinuxServer ~]# echo $?
0

3.2 expr 語句-字符串測試和數值測試

通常用於整數值,也能夠用於字符串;
格式:expr argument operator argument
expr 也是個手工命令行的計數器

$ expr  10 + 10                    #注意空格
$ expr 300 /  6  /  5   
$ expr 30  \*  3                   #注意:乘號必須用反斜線屏蔽其特定含義

expr在循環中用於增量計算,首選,循環初始化爲0,而後循環加1,經常使用的作法:從expr接受輸出賦給循環變量
例:

$ LOOP=0
$ LOOP=`expr $LOOP + 1`

3.2.1 數值測試

能夠用expr測試一個數,若是對非整數進行計算,則返回錯誤
例:

$ expr  1.1 + 1          #返回錯誤
$ expr  1 + 1            #返回2

3.2.2 字符串測試

注 expr 也有返回的狀態,但與系統最後返回的值恰好相反,expr返回成功爲1,其餘值爲失敗。
例:

$ value=hello
$ expr $value =  "hello"
1                             # 這是expr執行成功的值
$ echo $?
0                             # 這是系統返回的成功的值

3.3 if 條件判斷

格式:

if 條件1 
   then   命令1
elif  條件2
   then  命令2
else  命令3                 
fi

注意:使用if語句時,必須將then部分放在新行,不然會產生錯誤,若是要不分行,必須使用命令分割符,即:

if  條件1; then
    命令1
fi

例:$ vi myfile

#!/bin/sh
DIRECTORY=$1
if [ "`ls -A $DIRECTORY`" = "" ] ;  then
   echo  "$DIRECTORY  is  indeed empty"
else
   echo  "$DIRECTORY  is  not  empty"
fi

3.4 for 循環

格式:

for 變量名 in 列表
do
    命令1
    命令2
done

說明:命令 可爲任何有效的shell命令和語句
變量名能夠爲任何單詞
in列表是可選的,若是沒有列表,for循環會使用命令行的位置參數
in列表能夠包含替換,字符串,文件名

例:

#!/bin/sh
for loop1 in 1 2 4 5 6           #數字列表
do 
   echo $loop1
done
for loop2  in he is a tall man   #字符串列表
do 
   echo $loop2
done
for loop3 in `ls`                #替換列表
do 
  echo $loop3
done

對for 循環使用參數,當循環中省去in列表選項時,它將接受命令行特定變量作爲參數即

for params in "$@"   或者 for params in "$*"

例1:

#!/bin/sh
for  params in "$@"
do
echo  "You supplied $params as a command line option"
done
echo  $params

例2

#!/bin/sh
counter=0
for files in `ls`
do
counter = `expr $counter  +  1`
done
echo  "There are $counter  files in `pwd`"

3.5 while和until循環

while循環
格式:

while  命令
do    
      命令1
      命令2
      ……
done

note:do和done之間命令,只有前一個返回狀態爲0,後面命令纔會被執行;不然則循環停止

until循環
格式:

until  條件
       命令1
       命令2
       ……
done

note:until執行一系列命令,只至條件爲真時中止,循環至少執行一次。

例1:

#!/bin/sh
echo "Type  <Ctrl-D> to terminate"
echo  -n  "enter your favorate film :"
while read  FILM
do 
   echo "Yeah,great film the $FILM"
done

使用ctrl-D中斷腳本的執行,整個循環停止
例2:

#!/bin/sh
IS_ROOT=`who | grep root`
until [ "$IS_ROOT" ]
do
    sleep 5
    IS_ROOT=`who | grep root`
done
echo "Watch it. Roots in " | mail wuxh

思考:爲何用sleep 5?

3.6 case 條件選擇

格式:

case  值  in 
      模式1)
            命令1
            ……
            ;;
      模式2)
            命令2
            ……
            ;;
esac

case 取值後面必須爲in,每一個模式必須以右括號結束,取值能夠爲變量或者常數,找到匹配模式後,執行相關命令直到;;

模式部分能夠包含元字符,與命令行中文件擴展名中使用的匹配類型相符,如 * ? [..]
例:

#!/bin/sh
if [  $# != 1 ];  then
      echo "Usage:`basename $0` [start|stop|help]"                  	
      exit 1
fi
OPT=$1
      case $OPT in
      start) 
            echo "starting..`basename $0`"
            # code here to start a process
            ;;
      stop) 
            echo "stopping..`basename $0`"
            # code here to stop a process
            ;;
      help)
            # code here to display a help page
            ;;
      *) 
            echo "Usage:`basename $0` [start|stop|help]"
            ;;
      esac

3.7 Break 和continue

有時須要某些準則退出循環或者跳過循環步,就須要break和continue來實現
break 容許跳出循環或者case語句,在嵌套循環裏,能夠制定跳出的循環個數,例在兩層的嵌套循環內,break 2能夠跳出整個循環
continue 相似於break,區別是continue只會跳過當前的循環步,而不會跳出整個循環
例子1:

#!/bin/sh
while :
do 
echo -n  "Enter any number [1..5]  :"
read ANS
case $ANS  in
      1|2|3|4|5) 
            echo "great you entered a number between 1 and 5"
            ;;
      *) 
            echo "wrong number..bye"
            break
            ;;
esac
done

例子2 :
names2.txt 內容包含僱員名字,部門,及其id,以下所示:
------------------------------內容以下--------------------------------
---LISTING OF PERSONNEL FILE----
--- TAKEN AS AT 06/1999----------------
Louise Conrad:Accounts:ACC8987
Peter James:Payroll:PR489
Fred Terms:Customer:CUS012
James Lenod:Accounts:ACC887
Frank Pavely:Payroll:PR489
-------------------------------------------------------------------------------
要求:讀取names2.txt文件,將在職員工的名字,部門,部門id讀取打印出來
說明:Peter James已經離職

使用IFS讀文件
輸出時要去除冒號域分隔符,可以使用變量IFS。在改變它以前保存IFS的當前設置。而後在腳本執行完後恢復此設置。
使用IFS能夠將域分隔符改成冒號而不是空格或t a b鍵,這裏有3個域須要加域分隔,即NAME、DEPT和ID。腳本以下:

#!/bin/sh
# save the setting of IFS
SAVEDIFS=$IFS
# assign new separator to IFS
IFS=:
INPUT_FILE=names2.txt
NAME_HOLD="Peter James"
LINE_NO=0
if [ -s  $INPUT_FILE ]; then
    while  read NAME  DEPT  ID
    do
        LINE_NO=`expr $LINE_NO  +  1`
        if [   "$LINE_NO"  -le  "2"  ];  then
            continue
        fi 
        if  [   "$NAME" = "$NAME_HOLD"  ];  then 
            continue
        else
            echo "Now processing …$NAME $DEPT $ID"
        fi
    done < $INPUT_FILE
    # restore the settings of IFS
    IFS=$SAVEDIFS
else
    echo "`basename $0 `  : Sorry file not found or there is no data in the file >&2"
    exit 1
fi

第四部分 Shell 函數

Shell 容許將一組命令集或語句造成一個可用塊,這些塊稱爲shell函數,其組成部分:
函數標題,函數體
標題是函數名,應該惟一;函數體是命令集合
函數格式:

函數名()
{
   命令1
   …
}
或者  
function 函數名()
               { ….
               }

函數能夠只放在同一個文件中作爲一段代碼,也能夠放在只包含函數的單獨文件中

4.1 在腳本中定義並使用函數

注:函數必須在使用前定義,通常放於腳本開始部分,直至shell解釋器首次發現它時,纔可使用

例腳本func1:

#!/bin/sh
hello() {
echo "Hello,today’s date is `date`"
}
echo "now, going to the function hello"
hello                       
echo "back from the function"

4.2 向函數傳遞參數

向函數傳遞參數就象在通常腳本中使用特殊變量$1,$2..\(9同樣,函數取得所傳參數後,將原始參數傳回shell,能夠在函數內定義本地變量保存所傳的參數,通常這樣的參數名稱以_開頭 例:腳本對輸入的名字進行檢查,只能包含字母 \) vi func2

#!/bin/sh
echo -n "what is your first name :"
read F_NAME
char_name()
{  
_LETTERS_ONLY=$1
_LETTERS_ONLY=`echo $1|awk  '{if($0~/[^a-z A-Z]/)  print  "1"}'`
if [ "$_LETTERS_ONLY" != "" ]
then       
    return 1
else
    return 0
fi
}
if  char_name  $F_NAME;  then
    echo "ok"
else
    echo "ERRORS"
fi

4.3 函數返回值

函數執行完畢或者基於某個測試語句返回時,可做兩種處理:

  1. 讓函數正常執行到末尾,而後返回腳本中調用函數的控制部分
  2. 使用return 返回腳本中函數調用的下一條語句,能夠帶返回值,
  • 0爲無錯誤
  • 1爲有錯誤
    格式:
return     從函數中返回,用最後狀態命令決定返回值
return 0  無錯誤返回
return 1  有錯誤返回

4.4 函數返回值測試:

能夠直接在腳本調用函數語句的後面使用最後狀態命令來測試函數
調用的返回值
例:

hello            #這裏是hello函數被調用
if [  $? = 0   ]  
then 
      echo 「it is ok」
else
      echo 「something is wrong with hello function」
fi

更好的辦法是使用if語句測試返回0仍是返回1,能夠在if語句裏面將函數調用用括號括起來,增長可讀性,如 if hello ; then

若是函數將從測試結果中反饋輸出,可使用替換命令保存結果,函數調用的替換格式爲
variable_name=function_name
函數function_name輸出被設置到變量variable_name中

4.5 在shell中使用函數

經常使用的一些函數能夠收集起來,放入函數文件,使用時,將文件載入shell中
文件頭應該以#!/bin/sh開頭,文件名可任意選取,但建議有說明性。
文件一旦載入shell,就能夠在命令行或者腳本中調用函數,可使用set產看全部定義的函數,輸出列表包括已經載入shell的全部函數。
要想改動文件,首先用unset命令從shell中刪除函數,注,這裏不是真正的刪除,修改完畢後,再將文件從新載入,有些shell會識別改動,沒必要使用unset,但建議改動時使用unset命令

4.6 建立函數文件

例:function.main

#!/bin/sh
findit() {
if [ $# -lt 1 ];  then
    echo "Usage :findit  file"     # 思考:爲何用findit,不用$0?
    return  1
fi
find  /  -name  $1  -print
}

4.7 定位文件(載入文件)

格式:<點><空格><路徑><文件名>

$.   ./function.main

4.8 檢查載入的函數

使用set命令查看已經載入shell中的函數

$ set

4.9 執行shell函數

要執行函數,簡單的鍵入函數名,若是須要參數,後跟參數便可

$ findit hello

4.10 修改shell函數

若是須要對函數作改動,須要藉助unset命令先從shell中刪除函數,修改後,再從新載入

$ unset findit
修改…
$ .  ./function.main

第五部分 腳本調試 ——Shell腳本調試

5.1 通常的shell腳本錯誤

  • a.循環錯誤
    • 如for,while,until,case等結構中漏寫了某個保留字
  • b.漏寫引號
  • c.測試錯誤
    • 如 在-eq 兩邊應該使用數字取值;[變量] 缺乏空格
  • d.字符大小寫
    -linux對大小寫敏感

5.2 使用set命令進行調試

set  -n  讀命令但不執行
set  -v  顯示讀取的全部行
set  -x  顯示全部命令及其參數
set  +x  set選項關閉

例:vi error_file

#!/bin/sh
set –x
LIST="Peter Susan John Barry Lucy Norman Bill Leslie"
echo  -n  "Enter your name :"
read NAME
for LOOP in $LIST
do
if  [ "$LOOP" = "$NAME" ];then
    echo "you’re on the list, you’re in"
    break
fi
done
set +x

運行腳本

$ ./error_file

執行結果:

error  
+ error
+ LIST=Peter Susan John Barry Lucy Norman Bill Leslie
+ echo –n Enter your Name:
Harry
+ [ Peter = Harry ]
+ [ Susan = Harry  ]
+ [ John = Harry  ]
+ [ Barry = Harry  ]
+ [ Lucy = Harry  ]
+ [ Norman = Harry  ]
+ [ Bill = Harry  ]
+ [ Leslie = Harry  ]
相關文章
相關標籤/搜索