第一部分:Linux Shell 簡介
Shell 是一個用 C 語言編寫的程序,它是用戶使用 Linux 的橋樑。Shell 既是一種命令語言,又是一種程序設計語言。
Shell 是指一種應用程序,這個應用程序提供了一個界面,用戶通過這個界面訪問操作系統內核的服務。
Ken Thompson 的 sh 是第一種 Unix Shell,Windows Explorer 是一個典型的圖形界面 Shell。
當一個用戶登陸linux 系統後,系統就會為該用戶創建一個shell程序。
Shell的版本:
- 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 換行
note:
對於linux系統,必須使用-e選項來使以上轉義符生效
例:
$ echo -e "hello\tboy"
hello boy
echo命令對特殊字符敏感,如果要輸出特殊字符,需要用\屏蔽其特殊含義。
常用的特殊字符:雙引號”” 反引號“ 反斜線\
例:
$ 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:
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:該命令一次顯示完整個文件,若想分頁查看,需使用more
格式: cat [ options ] filename1 … filename2 …
常用options:
- -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腳本或者命令
在大的系統中,系統管理員可以通過/etc/cron.allow和/etc/cron.deny這兩個文件來禁止或允許用戶擁有自己的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,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 創建一個文件,建議名為
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/
$ 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 系統變量
系統變量適用於所有用戶進程,可以在命令行中設置,但用戶註銷時這些值將丟失,最好在.bash_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 條件
do
命令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 chenshifeng
思考:為什麼用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可以將域分隔符改為冒號而不是空格或tab鍵,這裡有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 函數返回值
函數執行完畢或者基於某個測試語句返回時,可作兩種處理:
- 讓函數正常執行到末尾,然後返回腳本中調用函數的控制部分
- 使用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 ]