1. 程式人生 > >Linux shell指令碼基礎學習詳細介紹(完整版)2

Linux shell指令碼基礎學習詳細介紹(完整版)2

詳細介紹Linux shell指令碼基礎學習(五)

Linux shell指令碼基礎前面我們在介紹Linux shell指令碼的控制流程時,還有一部分內容沒講就是有關here document的內容這裡繼續。

Linux shell指令碼基礎已經被分成好幾個部分了,這裡對控制流程的內容也就馬上講完了,這是最後一部分關於here document,這裡舉例稍微有點複雜,我們慢慢來分析這個複雜Linux shell指令碼。

6. Here documents

當要將幾行文字傳遞給一個命令時,here documents(譯者注:目前還沒有見到過對該詞適合的翻譯)一種不錯的方法。對每個指令碼寫一段幫助性的文字是很有用的,此時如果我們四有那個 here documents就不必用echo函式一行行輸出。 一個 "Here document" 以 << 開頭,後面接上一個字串,這個字串還必須出現在here document的末尾。下面是一個例子,在該例子中,我們對多個檔案進行重新命名,並且使用here documents列印幫助:

#!/bin/sh

# we have less than 3 arguments. Print the help text:

if [ $# -lt 3 ] ; then

cat <

ren -- renames a number of files using sed regular expressions

USAGE: ren 'regexp' 'replacement' files...

EXAMPLE: rename all *.HTM files in *.html:

ren 'HTM$' 'html' *.HTM

HELP

exit 0

fi

OLD="$1"

NEW="$2"

# The shift command removes one argument from the list of

# command line arguments.

shift

shift

# $* contains now all the files:

for file in $*; do

if [ -f "$file" ] ; then

newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"`

if [ -f "$newfile" ]; then

echo "ERROR: $newfile exists already"

else

echo "renaming $file to $newfile ..."

mv "$file" "$newfile"

fi

fi

done

這是一個複雜一些的例子。讓我們詳細討論一下。第一個if表示式判斷輸入命令列引數是否小於3個 (特殊變數$# 表示包含引數的個數) 。如果輸入引數小於3個,則將幫助文字傳遞給cat命令,然後由cat命令將其列印在螢幕上。列印幫助文字後程序退出。如果輸入引數等於或大於3個,我們 就將第一個引數賦值給變數OLD,第二個引數賦值給變數NEW。下一步,我們使用shift命令將第一個和第二個引數從引數列表中刪除,這樣原來的第三個 引數就成為引數列表$*的第一個引數。然後我們開始迴圈,命令列引數列表被一個接一個地被賦值給變數$file。接著我們判斷該檔案是否存在,如果存在則 通過sed命令搜尋和替換來產生新的檔名。然後將反短斜線內命令結果賦值給newfile。這樣我們就達到了我們的目的:得到了舊檔名和新檔名。然 後使用mv命令進行重新命名。這樣就明瞭這個複雜的Linux shell指令碼了吧。

詳細介紹Linux shell指令碼基礎學習(六)

Linux shell指令碼基礎學習我們這裡就差不多講完了,最後一部分內容是關於函式的,這就差不多把基礎部分介紹完了,後面還會有例項。

4)函式

如果您寫了一些稍微複雜一些的程式,您就會發現在程式中可能在幾個地方使用了相同的程式碼,並且您也會發現,如果我們使用了函式,會方便很多。一個函式是這個樣子的:

functionname()

{

# inside the body $1 is the first argument given to the function

# $2 the second ...

body

}

您需要在每個程式的開始對函式進行宣告。

下面是一個叫做xtitlebar的指令碼,使用這個指令碼您可以改變終端視窗的名稱。

這裡使用了一個叫做help的函式。正如您可以看到的那樣,這個定義的函式被使用了兩次。

#!/bin/sh

# vim: set sw=4 ts=4 et:

help()

{

cat <

xtitlebar -- change the name of an xterm, gnome-terminal or kde konsole

USAGE: xtitlebar [-h] "string_for_titelbar"

OPTIONS: -h help text

EXAMPLE: xtitlebar "cvs"

HELP

exit 0

}

# in case of error or if -h is given we call the function help:

[ -z "$1" ] && help

[ "$1" = "-h" ] && help

# send the escape sequence to change the xterm titelbar:

echo -e "33]0;$107"

#

在指令碼中提供幫助是一種很好的程式設計習慣,這樣方便其他使用者(和您)使用和理解指令碼。

命令列引數

我們已經見過$* 和 $1, $2 ... $9 等特殊變數,這些特殊變數包含了使用者從命令列輸入的引數。迄今為止,我們僅僅瞭解了一些簡單的命令列語法(比如一些強制性的引數和檢視幫助的-h選項)。 但是在編寫更復雜的程式時,您可能會發現您需要更多的自定義的選項。通常的慣例是在所有可選的引數之前加一個減號,後面再加上引數值 (比如檔名)

有好多方法可以實現對輸入引數的分析,但是下面的使用case表示式的例子無遺是一個不錯的方法。

#!/bin/sh

help()

{

cat <

This is a generic command line parser demo.

USAGE EXAMPLE: cmdparser -l hello -f -- -somefile1 somefile2

HELP

exit 0

}

while [ -n "$1" ]; do

case $1 in

-h) help;shift 1;; # function help is called

-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

echo "opt_f is $opt_f"

echo "opt_l is $opt_l"

echo "first arg is $1"

echo "2nd arg is $2"

您可以這樣執行該指令碼:

cmdparser -l hello -f -- -somefile1 somefile2

返回的結果是:

opt_f is 1

opt_l is hello

first arg is -somefile1

2nd arg is somefile2

這個指令碼是如何工作的呢?指令碼首先在所有輸入命令列引數中進行迴圈,將輸入引數與case表示式進行比較,如果匹配則設定一個變數並且移除該引數。根據unix系統的慣例,首先輸入的應該是包含減號的引數。

詳細介紹Linux shell指令碼基礎學習(七)

Linux shell指令碼基礎的學習理論知識已經講完了,後面是兩個具體的例項,這裡先說第一個關於二進位制何時禁止之間的轉換。

Linux shell指令碼基礎學習這部分如果只看前面間的理論部分雖然有一些例子,但是還不夠系統,這裡將以具體例項給大家展現Linux shell指令碼程式設計,以幫助大家完善Linux shell基礎的學習和提高。

第2部分 例項

現在我們來討論編寫一個指令碼的一般步驟。任何優秀的指令碼都應該具有幫助和輸入引數。並且寫一個偽指令碼(framework.sh),該指令碼包含了大多數指令碼都需要的框架結構,是一個非常不錯的主意。這時候,在寫一個新的指令碼時我們只需要執行一下copy命令:

cp framework.sh myscript

然後再插入自己的函式。

讓我們再看個例子:

二進位制到十進位制的轉換

指令碼 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"


該指令碼使用的演算法是利用十進位制和二進位制數權值 (1,2,4,8,16,..),比如二進位制"10"可以這樣轉換成十進位制:

0 * 1 + 1 * 2 = 2

為了得到單個的二進位制數我們是用了lastchar 函式。該函式使用wc –c計算字元個數,然後使用cut命令取出末尾一個字元。Chop函式的功能則是移除最後一個字元。

這個Linux shell指令碼例項幫我們完成了轉換,下一次我們將舉例一個檔案迴圈程式。

詳細介紹Linux shell指令碼基礎學習(八)

Linux shell指令碼基礎學習例項前面說明了十進位制和二進位制的轉換,這裡舉最後一個例子,關於檔案的迴圈,同時也說明一下如何除錯,來結束我們的課程。

Linux shell指令碼前面的例項是說明十進位制和二進位制的轉換,還以一個有關檔案迴圈的例項來結束這部分內容的學習。相信Linux shell指令碼的基礎學習的學習者應該能夠掌握一些簡單的Linux shell指令碼的編寫。
檔案迴圈程式

或許您是想將所有發出的郵件儲存到一個檔案中的人們中的一員,但是在過了幾個月以後,這個檔案可能會變得很大以至於使對該檔案的訪問速度變慢。下面的 指令碼rotatefile可
以解決這個問題。這個指令碼可以重新命名郵件儲存檔案(假設為outmail)為outmail.1,而對於 outmail.1就變成了outmail.2 等等等等...

複製程式碼 程式碼如下:
#!/bin/sh
# vim: set sw=4 ts=4 et:
ver="0.1"
help()
{
cat <
rotatefile -- rotate the file name
USAGE: rotatefile [-h] filename
OPTIONS: -h help text
EXAMPLE: rotatefile out
This will e.g rename out.2 to out.3, out.1 to out.2, out to out.1
and create an empty out-file
The max number is 10
version $ver
HELP
exit 0
}
error()
{
echo "$1"
exit 1
}
while [ -n "$1" ]; do
case $1 in
-h) help;shift 1;;
--) break;;
-*) echo "error: no such option $1. -h for help";exit 1;;
*) break;;
esac
done
# input check:
if [ -z "$1" ] ; then
error "ERROR: you must specify a file, use -h for help"
fi
filen="$1"
# rename any .1 , .2 etc file:
for n in 9 8 7 6 5 4 3 2 1; do
if [ -f "$filen.$n" ]; then
p=`expr $n + 1`
echo "mv $filen.$n $filen.$p"
mv $filen.$n $filen.$p
fi
done
# rename the original file:
if [ -f "$filen" ]; then
echo "mv $filen $filen.1"
mv $filen $filen.1
fi
echo touch $filen
touch $filen

這個指令碼是如何工作的呢?在檢測使用者提供了一個檔名以後,我們進行一個9到1的迴圈。檔案9被命名為10,檔案8重新命名為9等等。迴圈完成之後,我們將原始檔案命名為檔案1
同時建立一個與原始檔案同名的空檔案。

除錯

最簡單的除錯命令當然是使用echo命令。您可以使用echo在任何懷疑出錯的地方列印任何變數值。這也是絕大多數的shell程式設計師要花費80%的時間來除錯程式的原因。Shell程式的
好處在於不需要重新編譯,插入一個echo命令也不需要多少時間。

shell也有一個真實的除錯模式。如果在指令碼"strangescript" 中有錯誤,您可以這樣來進行除錯:

sh -x strangescript

這將執行該指令碼並顯示所有變數的值。

shell還有一個不需要執行指令碼只是檢查語法的模式。可以這樣使用:

sh -n your_script

這將返回所有語法錯誤

這裡Linux shell指令碼基礎學習就全部結束了。感謝大家的支援。