SHELL編程[Bash編程手冊]


 

============================== SHELL編程 ==============================

 

一、Shell語法
  1.1、變量聲明
  1.2、數組聲明和使用
  1.3、特殊的變量
  1.4、運算和運算符
      1.4.1、整數運算符
  1.5、流程語句
      1.5.1、if 語句
      1.5.2、case語句
      1.5.3、select 語句
  1.6、循環語句
      1.6.1、for語句
      1.6.2、while 語句
      1.6.3、breake 和continue
      1.6.4、shift
二、函數
三、shell程序調試
四、信號
五、bash中常用的命令

 

=============== 一、Shell語法 ===============

 

1.1、變量聲明

 

變量=值 (注意:等號兩側不能有空格)
a=”hello”
b=9
unset a 撤銷變量 a
readonly a=2 聲明靜態的變量 a=2 ,不能 unset
export 變量名 可把變量提升為全局環境變量,可供其他shell程序使用

 

變量應用中要注意:
echo “$1 = $1 ; $2 = $2 “; 屏蔽$1 ,屏蔽 $2 ,直接顯示 $1 ,$2,同理*也屏蔽了 * 的通配符作用
${SAT}day ,變量要與字符串連在一起時,應該用 ${}
a= `ls -al` 反引號,運行里面的命令,並把結果返回給變量a
a=$(ls -al) 等價於反引號
單引號‘’和雙引號“”的區別,單引號完全屏蔽 $a 變量,雙引號不屏蔽$a,單引號和雙引號都屏蔽 * 的通配符作用。

 

1.2、數組聲明和使用

1 name[0]="Tom"
2 name[1]="Tomy"
3 name[2]="John"
4 5 name=("Tom" "Tomy" "John")

例子:

 

 

1 #!/bin/bash
2 name=("Tom" "Tomy" "John")
3 for i in 0 1 2
4 do
5    echo $i:${name[$i]}
6 done

 

1.3、特殊的變量

 

$0:腳本名字。此變量包含地址,可以使用basename $0獲得腳本名稱。
$1:第一個參數
$2,$3,$4,$5,…一次類推。
$# 傳遞到腳本的參數個數
$* 以一個單字符串顯示所有向腳本傳遞的參數,,以(“$1 $2…”)
$$ 腳本運行的ID號
$! 后台運行的最后一個進程的ID號
$@ 與$*相同,但是使用時加引號,並在引號中返回每個參數。(“$1″”$2″…)
$- 顯示shell使用的當前選項。
$? 顯示最后命令的推出狀況。0表示沒有錯誤。

 

例子:

 

 

 1 #!/bin/sh
 2 if [ $# -ne 2 ] ; then
 3    echo "Usage: $0 string file";
 4    exit 1;
 5 fi
 6 grep $1 $2 ;
 7 if [ $? -ne 0 ] ; then
 8    echo "Not Found "$1" in $2";
 9    exit 1;
10 fi
11 echo "Found "$1" in $2";

 

上面的例子中使用了$0 $1 $2 $# $? 等變量,下面是程序的解釋:

判斷運行參數個數,如果不等於2,顯示使用”用法幫助”, 其中 $0 表示就是腳本自己。
用grep 在$2 文件中查找$1 字符串。
判斷前一個命令運行后的返回值(一般成功都會返回0, 失敗都會返回非0)。
如果沒有成功顯示沒找到相關信息,否則顯示找到了。
其中”表示轉義,在”" 里面還需要顯示”號,則需要加上轉義符”

 

參數置換的變量
1、變量=${參數:-word}:如果設置了參數,則用參數的值置換變量的值,否則用word置換。即這種變量的值等於某一個參數的值,如果該參數沒有設置,則變量就等於word的值。
[ -z "${COLUMNS:-}" ] && COLUMNS=80
2、變量=${參數:=word}:如果設置了參數,則用參數的值置換變量的值,否則把變量設置成word,然后再用word替換參數的值。注意,位置參數不能用於這種方式,因為在Shell程序中不能為位置參數賦值。
3、變量=${參數:?word}:如果設置了參數,則用參數的值置換變量的值,否則就顯示word並從Shell中退出,如果省略了word,則顯示標准信息。這種變量要求一定等於某一個參數的值。如果該參數沒有設置,就顯示一個信息,然后退出,因此這種方式常用於出錯指示。
4、變量=${參數:+word}:如果設置了參數,則用word置換變量,否則不進行置換。

 

字符串匹配的操作:

 

${PARAMETER#WORD} shell 像文件名擴展中那樣擴展 WORD,並從 PARAMETER 擴展后的值的開頭刪除最短的匹配模式(若存在匹配模式的話)。使用 ‘@’ 或 ‘$’ 即可刪除列表中每個參數的模式。
${PARAMETER##WORD} 導致從開頭刪除最長的匹配模式而不是最短的匹配模式。
${PARAMETER%WORD} shell 像文件名擴展中那樣擴展 WORD,並從 PARAMETER 擴展后的值末尾刪除最短的匹配模式(若存在匹配模式的話)。使用 ‘@’ 或 ‘$’ 即可刪除列表中每個參數的模式。
${PARAMETER%%WORD} 導致從末尾刪除最長的匹配模式而不是最短的匹配模式。
${PARAMETER/PATTERN/STRING} shell 像文件名擴展中那樣擴展 PATTERN,並替換 PARAMETER 擴展后的值中最長的匹配模式(若存在匹配模式的話)。為了在 PARAMETER 擴展后的值開頭匹配模式,可以給 PATTERN 附上前綴 #,如果要在值末尾匹配模式,則附上前綴 %。如果 STRING 為空,則末尾的 / 可能被忽略,匹配將被刪除。使用 ‘@’ 或 ‘$’ 即可對列表中的每個參數進行模式替換。
${PARAMETER//PATTERN/STRING} 對所有的匹配(而不只是第一個匹配)執行替換。

 

變數設定方式 str 沒有設定 str 為空字串 str 已設定非為空字串

 

 

 1 var=${str-expr} var=expr var= var=$str
 2 var=${str:-expr} var=expr var=expr var=$str
 3 var=${str+expr} var= var=expr var=expr
 4 var=${str:+expr} var= var= var=expr
 5 var=${str=expr} str=expr
 6 var=expr str 不變
 7 var= str 不變
 8 var=$str
 9 var=${str:=expr} str=expr
10 var=expr str=expr
11 var=expr str 不變
12 var=$str
13 var=${str?expr} expr 輸出至 stderr var= var=str
14 var=${str:?expr} expr 輸出至 stderr expr 輸出至 stderr var=str
15  
16  
17 [subsir@pinguino ~]$ x="a1 b1 c2 d2"
18 [subsir@pinguino ~]$ echo ${x#*1}
19 b1 c2 d2
20 [subsir@pinguino ~]$ echo ${x##*1}
21 c2 d2
22 [subsir@pinguino ~]$ echo ${x%1*}
23 a1 b
24 [subsir@pinguino ~]$ echo ${x%%1*}
25 a
26 [subsir@pinguino ~]$ echo ${x/1/3}
27 a3 b1 c2 d2
28 [subsir@pinguino ~]$ echo ${x//1/3}
29 a3 b3 c2 d2
30 [subsir@pinguino ~]$ echo ${x//?1/z3}
31 z3 z3 c2 d2

 

字符串子集提取:

${x:3:5}
的值就是 “e val”,
清單 9. shell 參數值的子字符串

 

 

1 [subsir@pinguino ~]$ x="some value"
2 [subsir@pinguino ~]$ echo "${x:3:5}"
3 e val

 

字符串長度:

您已經知道 $# 表示參數的數量,而 ${PARAMETER:OFFSET:LENGTH} 擴展適用於單個參數以及 $* 和 $@,因此,可以使用一個類似的結構體 ${#PARAMETER} 來確定單個參數的長度也就不足為奇了。清單 10 中所示的簡單的 testlength 函數闡明了這一點。自己去嘗試使用它吧。
清單 10. 參數長度

 

 

1 [subsir@pinguino ~]$ testlength () { for p in "$@"; do echo ${#p};done }
2 [subsir@pinguino ~]$ testlength 1 abc "def ghi"
3 1
4 3
5 7

 

1.4、運算和運算符

 

1.4.1、整數運算符

 

整數的算術運算符
+ - * / %
賦值運算符
+= -= * = / = %=
位運算符
<< >> & | ~ ^
位運算賦值運算符
<< = >> = & = | = ~ = ^ =
邏輯運算符:
&& || ! > > = < < = != ==

 

expr命令計算一個表達式的值
格式 :expr arg
例子:
計算(2 +3 )×4 的值
1 、分步計算,即先計算2 +3 ,再對其和乘4
s=`expr 2 + 3`
expr $s * 4
2 、一步完成計算:
expr `expr 2 + 3 ` * 4
說明:
運算符號和參數之間要有空格分開;
通配符號(* ), 在作為乘法運算符時要用 、“” 、‘’ 符號修飾

 

關鍵字let計算表達式的值:
#!/bin/bash
x=2006
let "x = $x + 1"
echo $x
x="a string."
echo $x

 

又出現了新的關鍵字:let。關於整數變量計算,有如下幾種:" + - * / % ",他們的意思和字面意思相同,在*和/之前必須冠以反斜線,已防被SHELL先行解釋。整數運算一般通過 let 和 expr 這兩個指令來實現,如對變量 x 加 1 可以寫作:let "x = $x + 1" 或者 x=`expr $x + 1`

 

1.4.2、邏輯運算符

 

對應操作 整數 字符串
相同 -eq =
不同 -ne !=
大於 -gt >
小於 -lt <
大於或等於 -ge
小於或等於 -le
為空 -z
不為空 -n

 

文件操作邏輯運算符:
-d file ----當file是一個目錄時,返回 True
-f file ----當file是一個普通文件時,返回 True
-r file ----當file是一個只讀文件時,返回 True
-s file ----當file文件長度大於0時,返回 True
-w file ----當file是一個可寫文件時,返回 True
-x "/bin/ls" ----當/bin/ls是一個可執行文件時,返回 True,目錄是否可訪問
-e file ----當file存在時,返回True
-o file ----當file文件的所有者是當前用戶時,返回True
-z file ----當file長度為0時,返回True
-u -----文件的 UID 標志被設置
-G -----文件的組 ID 和當前用戶相同
file1 -nt file2 -----文件 file1 比 file2 更新
file1 -ot file2 -----文件 file1 比 file2 更老

 

邏輯連接符:
! expr 當expr的值是False時,返回True
Expr1 -a expr2 當expr1,expr2值同為True時,返回True
Expr1 -o expr2 當expr1,expr2的值至少有一個為True時,返回True

 

命令邏輯連接符:
[ -r "$mailfolder" ]||{ echo "Can not read $mailfolder" ; exit 1; }
使用{}把兩個命令括起來,表示一個函數的用法。 && 與 ||或
[ -f "/etc/shadow" ] && echo "This computer uses shadow passwors"
注意:在“[”和“]”符號的左右都留有空格

 

例子:

 

 

1 #!/bin/sh
2 mailfolder=/var/spool/mail/james
3 [ -r "$mailfolder" ]||{ echo "Can not read $mailfolder" ; exit 1; }
4 echo "$mailfolder has mail from:"
5 grep "^From " $mailfolder
6 其中 “^From“ 表示以 From 開頭的

 

1.5、流程語句


1.5.1、if 語句

 

 

 1 if [ 邏輯表達式 ]; then
 2  #command code
 3 elif [ 邏輯表達式 ]; then
 4  #commandcode
 5 else
 6   #commandcode
 7 fi

 

如果您為了簡潔,想把 then 和 if 放在一行,那就要這樣寫了:if [ expression ]; then。即在 then 前加一個“;”號。

 

 

1.5.2、case語句

 

case string1 in
str1 ) commands1;;
str2 ) commands2;;
*) commands3;;
esac

 

例子:

 

#file lf.gz
lf.gz: gzip compressed data, deflated, original filename,
last modified: Mon Aug 27 23:09:18 2001, os: Unix
腳本:

 

 

1 #!/bin/sh
2 ftype=`file "$1"`
3 case "$ftype" in
4    "$1: Zip archive"*) unzip "$1" ;;
5    "$1: gzip compressed"*) gunzip "$1" ;;
6    "$1: bzip2 compressed"*)bunzip2 "$1" ;;
7    *)  # * 通配符 代表其他
8    error "File $1 can not be uncompressed with smartzip";;
9 esac

 

例子:

 

 

 1 #!/bin/bash
 2 echo "Hit a key, then hit return."
 3 read Keypress
 4  
 5 case "$Keypress" in
 6    [a-z] ) echo "Lowercase letter";;
 7    [A-Z] ) echo "Uppercase letter";;
 8    [0-9] ) echo "Digit";;
 9    * ) echo "Punctuation, whitespace, or other";;
10 esac
11 exit 0

 

 

1.5.3、select 語句
尤其擅長於交互式使用。用戶可以從一組不同的值中進行選擇。

 

 

select var in … ; do
 break
done

 

例子:

 

 

1 #!/bin/sh
2 echo "What is your favourite OS?"
3 select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do
4     break
5 done
6 echo "You have selected $var"

 

#下面是該腳本運行的結果:

What is your favourite OS?
1) Linux
2) Gnu Hurd
3) Free BSD
4) Other
#? 1
You have selected Linux

 

1.6、循環語句
1.6.1、for語句

 

 

for var in 數組列表; do
 #command bolock
done

 

例子1:

 

 

1 #!/bin/bash
2 for var in A B C ; do
3  echo "var is $var"
4 done

 

例子2:

 

 

 1 #!/bin/sh
 2 #列出 RPM 的數目
 3 # 用法: showrpm rpmfile1 rpmfile2 ...
 4 # EXAMPLE: showrpm /cdrom/RedHat/RPMS/*.rpm
 5 for rpmpackage in $*; do
 6  if [ -r "$rpmpackage" ];then
 7   echo "== $rpmpackage =="
 8   rpm -qi -p $rpmpackage
 9  else
10   echo "ERROR: cannot read file $rpmpackage"
11  fi
12 done

 

例子3:

 

 

1 for var1 in "$@"
2 do
3    #statements
4 done

 

例2和例3的 $* 和“$@”是相同的

 

1.6.2、while 語句

 

while [ express ]; do
   #command
Done

 

例子1:

 

 

1 count=1
2 while [ -n "$*"]
3 do
4    echo "this is a parameter number $count $1"
5    shift
6    count='expr $count + 1'
7 done

 

例子2:

 

 

 1 while [ -n "$1" ]; do
 2 case $1 in
 3 -h) help;shift 1;; # function help is called
 4 # 執行 help 函數 , shift 1 表示,移除第一個變量 $1 ,則第二個變為: $1
 5   -f) opt_f=1;shift 1;; # variable opt_f is set
 6   -l) opt_l=$2;shift 2;; # -l takes an argument -> shift by 2
 7   --) shift;break;; # end of options
 8   -*) echo "error: no such option $1. -h for help";exit 1;;
 9   *) break;;
10 esac
11 done

 

就像平常執行命令一樣,當有參數-h 時,則執行相應的動作

 

1.6.3、breake 和continue

 

關鍵字”break” 用來跳出循環。而關鍵字”continue”用來不執行余下的部分而直接跳到下一個循環。

 

1.6.4、shift

 

shift將存放在位置變量中的命令行參數,依次向左傳遞.例如
位置變量當前值為:
$1=file1 $2=file2 $3=file3
執行一次shift命令后,位置變量的值為:
$1=file2 $2=file3
還可以在shift命令中指定位置變量轉移的次數, 如:
shift n
例子:

 1 while [ "$1"]
 2 do
 3    if [ "$1"="-i"] then
 4       infile=” $2 5       shift 2
 6    else if [ "$1"="-o"] then
 7       outfile=”$2 8       shift 2
 9    else
10       echo “Program $0 does not recognize option $111    fi
12 done

 

 

 

二、函數
腳本 b2d 將二進制數 (比如 1101) 轉換為相應的十進制數。這也是一個用expr命令進行數學運算的例子:

 

 

 1 #!/bin/sh
 2 # vim: set sw=4 ts=4 et:
 3 help()
 4 {
 5  cat < b2h -- convert binary to decimal
 6 USAGE: b2h [-h] binarynum
 7 OPTIONS: -h help text
 8 EXAMPLE: b2h 111010
 9 will return 58
10 HELP
11  exit 0
12 }
13  
14  
15 error()
16 {  # print an error and exit
17   echo "$1"
18   exit 1
19 }
20  
21 lastchar()
22 {  # return the last character of a string in $rval
23   if [ -z "$1" ]; then
24     # empty string
25     rval=""
26     return
27   fi
28   # wc puts some space behind the output this is why we need sed:
29   numofchar=`echo -n "$1" wc -c sed ''s/ //g'' `
30   # now cut out the last char
31   rval=`echo -n "$1" cut -b $numofchar`
32 }
33  
34 chop()
35 {  # remove the last character in string and return it in $rval
36   if [ -z "$1" ]; then
37     # empty string
38     rval=""
39     return
40   fi
41   # wc puts some space behind the output this is why we need sed:
42   numofchar=`echo -n "$1" wc -c sed ''s/ //g'' `
43   if [ "$numofchar" = "1" ]; then
44     # only one char in string
45     rval=""
46     return
47   fi
48   numofcharminus1=`expr $numofchar "-" 1`
49   # now cut all but the last char:
50   rval=`echo -n "$1" cut -b 0-${numofcharminus1}`
51 }
52  
53 while [ -n "$1" ]; do
54 case $1 in
55   -h) help;shift 1;; # function help is called
56   --) shift;break;; # end of options
57   -*) error "error: no such option $1. -h for help";;
58   *) break;;
59 esac
60 done
61  
62 # The main program
63 sum=0
64 weight=1
65 # one arg must be given:
66 [ -z "$1" ] && help
67 binnum="$1"
68 binnumorig="$1"
69  
70 while [ -n "$binnum" ]; do
71   lastchar "$binnum"
72   if [ "$rval" = "1" ]; then
73     sum=`expr "$weight" "+" "$sum"`
74   fi
75   # remove the last position in $binnum
76   chop "$binnum"
77   binnum="$rval"
78   weight=`expr "$weight" "*" 2`
79 done
80 echo "binary $binnumorig is decimal $sum"

 

=============== 三、shell程序調試 ===============

 

在編程過程中難免會出錯,有的時候,調試程序比編寫程序花費的時間還要多,Shell程序同樣如此。  Shell程序的調試主要是利用bash命令解釋程序的選擇項。
調用bash的形式是:  
bash -選擇項Shell程序文件名幾個常用的選擇項是:
  -e 如果一個命令失敗就立即退出。
  -n 讀入命令但是不執行它們。
  -u 置換時把未設置的變量看做出錯。
  -v 當讀入Shell輸入行時把它們顯示出來。
  -x 執行命令時把命令和它們的參數顯示出來。

 

=============== 四、信號 ===============

 

  trap命令用於在Shell程序中捕捉信號,之后可以有3種反應方式:
  (1)執行一段程序來處理這一信號。
  (2)接受信號的默認操作。
  (3)忽視這一信號。
  trap對上面3種方式提供了3種基本形式:
  第一種形式的trap命令在Shell接收到與signal list清單中數值相同的信號時,將執行雙引號中的命令串。
  trap ‘commands’ signal-list
  trap “commands” signal-list
  為了恢復信號的默認操作,使用第二種形式的trap命令:
  trap signal-list
  第三種形式的trap命令允許忽略信號:
  trap ” ” signal-list
  注意:
  (1)對信號11(段違例)不能捕捉,因為Shell本身需要捕捉該信號去進行內存的轉儲。
  (2)在trap中可以定義對信號0的處理(實際上沒有這個信號),Shell程序在其終止(如執行exit語句)時發出該信號。
  (3)在捕捉到signal-list中指定的信號並執行完相應的命令之后,如果這些命令沒有將Shell程序終止的話,Shell程序將繼續執行收到信號時所執行的命令后面的命令,這樣將很容易導致Shell程序無法終止。
  另外,在trap語句中,單引號和雙引號是不同的。當Shell程序第一次碰到trap語句時,將把commands中的命令掃描一遍。此時若commands是用單引號括起來的話,那么Shell不會對commands中的變量和命令進行替換,否則commands中的變量和命令將用當時具體的值來替換。

 

=============== 五、bash中常用的命令Alias |設置命令別名 ===============

 

Bg |將一個被掛起的進程在后台執行
cd |改變用戶的當前目錄
exit |終止一個shell
export |使作為這個命令的參數的變量及其當前值,在當前運行的shell的子進程中可見
fc |編輯當前的命令行歷史列表
fg |讓一個被掛起的進程在前台執行
help |顯示bash內部命令的幫助信息
history |顯示最近輸入的一定數量的命令行
kill |終止一個進程
pwd |顯示用戶當前工作目錄
unalias |刪除命令行別名




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM