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編程


一、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、數組聲明和使用name[0]="Tom"
name[1]="Tomy"
name[2]="John"

name=("Tom" "Tomy" "John")

例子:
#!/bin/bash
name=("Tom" "Tomy" "John")
for i in 0 1 2
do
echo $i:${name[$i]}

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

例子:
#!/bin/sh
if [ $# -ne 2 ] ; then
echo "Usage: $0 string file";
exit 1;
fi
grep $1 $2 ;
if [ $? -ne 0 ] ; then
echo "Not Found "$1" in $2";
exit 1;
fi
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 已設定非為空字串
var=${str-expr} var=expr var= var=$str
var=${str:-expr} var=expr var=expr var=$str
var=${str+expr} var= var=expr var=expr
var=${str:+expr} var= var= var=expr
var=${str=expr} str=expr
var=expr str 不變
var= str 不變
var=$str
var=${str:=expr} str=expr
var=expr str=expr
var=expr str 不變
var=$str
var=${str?expr} expr 輸出至 stderr var= var=str
var=${str:?expr} expr 輸出至 stderr expr 輸出至 stderr var=str


[ian@pinguino ~]$ x="a1 b1 c2 d2"
[ian@pinguino ~]$ echo ${x#*1}
b1 c2 d2
[ian@pinguino ~]$ echo ${x##*1}
c2 d2
[ian@pinguino ~]$ echo ${x%1*}
a1 b
[ian@pinguino ~]$ echo ${x%%1*}
a
[ian@pinguino ~]$ echo ${x/1/3}
a3 b1 c2 d2
[ian@pinguino ~]$ echo ${x//1/3}
a3 b3 c2 d2
[ian@pinguino ~]$ echo ${x//?1/z3}
z3 z3 c2 d2

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

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

字符串長度:
您已經知道 $# 表示參數的數量,而 ${PARAMETER:OFFSET:LENGTH} 擴展適用於單個參數以及 $* 和 $@,因此,可以使用一個類似的結構體 ${#PARAMETER} 來確定單個參數的長度也就不足爲奇了。清單 10 中所示的簡單的 testlength 函數闡明瞭這一點。自己去嘗試使用它吧。
清單 10. 參數長度
[ian@pinguino ~]$ testlength () { for p in "$@"; do echo ${#p};done }
[ian@pinguino ~]$ testlength 1 abc "def ghi"
1
3
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"
注意:在“[”和“]”符號的左右都留有空格

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


1.5、流程語句
1.5.1、if 語句

if [ 邏輯表達式 ]; then
 #command code
elif [ 邏輯表達式 ]; then
 #commandcode
else
  #commandcode
fi

if [ expression ]
then
#code block
elif [ expression ]
then
#code block
else
#code block
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
腳本:
#!/bin/sh
ftype=`file "$1"`
case "$ftype" in
"$1: Zip archive"*) unzip "$1" ;;
"$1: gzip compressed"*) gunzip "$1" ;;
"$1: bzip2 compressed"*)bunzip2 "$1" ;;
*) # * 通配符 代表其他
error "File $1 can not be uncompressed with smartzip";;
esac

例子:
#!/bin/bash
echo "Hit a key, then hit return."
read Keypress

case "$Keypress" in
[a-z] ) echo "Lowercase letter";;
[A-Z] ) echo "Uppercase letter";;
[0-9] ) echo "Digit";;
* ) echo "Punctuation, whitespace, or other";;
esac
exit 0

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

select var in ... ; do
 break
done

例子:
#!/bin/sh
echo "What is your favourite OS?"
select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do
    break
done
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:
#!/bin/bash
for var in A B C ; do
 echo "var is $var"
done

例子2:
#!/bin/sh
#列出 RPM 的數目
# 用法: showrpm rpmfile1 rpmfile2 ...
# EXAMPLE: showrpm /cdrom/RedHat/RPMS/*.rpm
for rpmpackage in $*; do
 if [ -r "$rpmpackage" ];then
  echo "== $rpmpackage =="
  rpm -qi -p $rpmpackage
 else
  echo "ERROR: cannot read file $rpmpackage"
 fi
done

例子3:
for var1 in "$@"
do
#statements
done
例2和例3的 $* 和“$@”是相同的

1.6.2、while 語句
while [ express ]; do
#command
Done

例子1:
count=1
while [ -n "$*"]
do
echo "this is a parameter number $count $1"
shift
count='expr $count + 1'
done

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

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


1.6.3、breake 和continue
關鍵字"break" 用來跳出循環。而關鍵字”continue”用來不執行餘下的部分而直接跳到下一個循環。

1.6.4、shiftshift將存放在位置變量中的命令行參數,依次向左傳遞.例如
位置變量當前值爲:
$1=file1 $2=file2 $3=file3
執行一次shift命令後,位置變量的值爲:
$1=file2 $2=file3
還可以在shift命令中指定位置變量轉移的次數, 如:
shift n
例子:
while [ "$1"]
do
if [ "$1"="-i"] then
infile=" $2"
shift 2
else if [ "$1"="-o"] then
outfile="$2"
shift 2
else
echo "Program $0 does not recognize option $1"
fi
done
tr a-z A-Z<$infile>$outfile


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

#!/bin/sh
# vim: set sw=4 ts=4 et:
help()
{
 cat < b2h -- convert binary to decimal
USAGE: b2h [-h] binarynum
OPTIONS: -h help text
EXAMPLE: b2h 111010
will return 58
HELP
 exit 0
}


error()
{  # print an error and exit
  echo "$1"
  exit 1
}

lastchar()
{  # return the last character of a string in $rval
  if [ -z "$1" ]; then
    # empty string
    rval=""
    return
  fi
  # wc puts some space behind the output this is why we need sed:
  numofchar=`echo -n "$1" wc -c sed ''s/ //g'' `
  # now cut out the last char
  rval=`echo -n "$1" cut -b $numofchar`
}

chop()
{  # remove the last character in string and return it in $rval
  if [ -z "$1" ]; then
    # empty string
    rval=""
    return
  fi
  # wc puts some space behind the output this is why we need sed:
  numofchar=`echo -n "$1" wc -c sed ''s/ //g'' `
  if [ "$numofchar" = "1" ]; then
    # only one char in string
    rval=""
    return
  fi
  numofcharminus1=`expr $numofchar "-" 1`
  # now cut all but the last char:
  rval=`echo -n "$1" cut -b 0-${numofcharminus1}`
}

while [ -n "$1" ]; do
case $1 in
  -h) help;shift 1;; # function help is called
  --) shift;break;; # end of options
  -*) error "error: no such option $1. -h for help";;
  *) break;;
esac
done

# The main program
sum=0
weight=1
# one arg must be given:
[ -z "$1" ] && help
binnum="$1"
binnumorig="$1"

while [ -n "$binnum" ]; do
  lastchar "$binnum"
  if [ "$rval" = "1" ]; then
    sum=`expr "$weight" "+" "$sum"`
  fi
  # remove the last position in $binnum
  chop "$binnum"
  binnum="$rval"
  weight=`expr "$weight" "*" 2`
done
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 |刪除命令行別名

發佈了19 篇原創文章 · 獲贊 5 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章