1. 程式人生 > >Shell(Bash)學習筆記(一)

Shell(Bash)學習筆記(一)

以前只是簡單看過一些文章,瞭解一些。平時也就是寫個簡單的命令組合啥的,沒寫過複雜的指令碼。最近一次為了恢復資料,寫了一下指令碼,發現這東西光學不練確實不行。順便記一下學習筆記備用。

約定:本文中的shell特指bash.

由於javaeye部落格編輯器沒有提供shell程式碼格式,就只好勉強用javascript指令碼格式插入程式碼。

一.變數

變數直接賦值,不用提前宣告。

var="Hello"
var=Hello
var='Hello'
 

注意幾點:

1.變數和值之間不能有空格,否則直譯器會認為是幾個命令。很多程式設計師的習慣是在=號兩邊留空格為了好看,但這點在shell中行不通。

2.字串不必用"號或者',上面的幾種賦值方式是等價的。除非字串之間有空格的時候。

如:

var="Hello World"
 

這時候就需要用引號。

3.

var=
 這樣的語句也是合法的,表示var的值為空。

4.使用變數的時候需要在變數前面加上$符號。這一點php程式設計師比較熟悉。

如:

echo $var
 

這也就是為什麼shell中的字串不必用引號的原因。你如果直接執行

echo var
 

系統會將var當作字串,而不是變數處理。在變數前加上$號還有個好處就是在字串中輸出變數的時候,直接在字串裡面用變數就行。

如:


var=World
var2="$var World"
echo $var2
 

但與php不同的是變數賦值的時候不用加$符號。因為shell中沒有==這個符號,判斷相等也是用=號。如果賦值的時候加上$號,會產生混淆。

還有一點要注意的就是單引號(')字串 中的變數不會被替換。

var=World
var2='$var World'
echo $var2

上面的語句輸出結果:$var World

這個可以用來輸出$等特殊符號,而不用擔心字元被當作變數替換。

二.語句

1.shell的語句不必用;號結束,除非是同一行寫幾個語句的時候。

2.shell中的語句塊不用{}號擴起來。if語句一般就用fi表示結束。當然這個也有特例,後面會提到。

3.if語句
if [ condition ]
then 
    action
elif [ condition2 ]
then 
    action2
.
.
.
elif [ condition3 ]
then 
else
    actionx
fi

需要注意的是shell中沒有elseif,而是elif(這個縮寫也太變態了吧,有必要麼?).

每個或者elif後跟著then,並且要換行或者用;分開。then可以和後面的action在一行。

3.for迴圈

var="one two three four"
for x in $var
do
     echo $x
done

 for迴圈用do  和 done表示開始結束,不要舉一反三,認為是用 rof結束。

4.while和util迴圈

while [ condition ]
 do
     statements
 done
 
until [ condition ]
 do
     statements
 done
 

5.條件語句

shell中的條件語句用[]號括起來,用於if,while,until等結構。

 條件判斷用=號,而不是==號。條件語句與[] 號之間要有空格分開。

如:

gender="boy"
if [ "$gender" = "girl" ]
then
      echo 'Welcome!'
else
      echo 'We only welcome girl.'
fi

還有要注意的是條件語句中=號兩旁要有空格分開,否則shell會將條件語句整個作為一個字串處理,條件永遠為真。條件語句中的變數最好用"號引起來,否則如果該變數中有空格,shell就會報too many arguments錯誤。如果變數正好為空,則會報 =: unary operator expected.錯誤。因為變數為空的話,條件語句少了一邊,當然會出錯。所以,將字串變數用雙引號括起來是shell程式設計的好習慣,尤其在條件語句中。

其他的比較符號,如 >,<,不能直接在條件語句中使用,因為>號在shell中有特殊含義。下面是shell的比較運算符號表示方法:

算術比較運算子

num1-eq num2 	等於	[ 3 -eq $mynum ]
num1-ne num2 	不等於	[ 3 -ne $mynum ]
num1-lt num2 	小於	[ 3 -lt $mynum ]
num1-le num2 	小於或等於	[ 3 -le $mynum ]
num1-gt num2 	大於	[ 3 -gt $mynum ]
num1-ge num2 	大於或等於	[ 3 -ge $mynum ]
 
字串比較運算子 

-z string 	如果 string長度為零,則為真 	[ -z "$myvar" ]
-n string 	如果 string長度非零,則為真 	[ -n "$myvar" ]
string1= string2 	如果 string1與 string2相同,則為真 	[ "$myvar" = "one two three" ]
string1!= string2 	如果 string1與 string2不同,則為真 	[ "$myvar" != "one two three" ]

6.case 語句

gender="boy" 
case "$gender" in
      boy)
            echo "We only welcome girl."
            ;;
      girl)
            echo 'Welcome !'
            ;;
      *)
            echo "unknow."
            ;;
 esac  

case語句的語法比較怪,乍一看比較彆扭。每個pattern用 半括號括起來,用;;結束。

三.算術

shell 預設是用來處理字串的,所以如果你直接執行:

echo 1+1

 它會直接輸出1+1,而不會輸出2。 如果需要計算表示式的值,則只需用"$((" 和 "))"將表示式 括起。

echo $((1+1))
 

四.函式

add(){
    result=0
    for n in $*
    do
        result=$(($result+$n))
    done
    return $result
}

 執行:

add 1 2 3
echo $?
echo $result

兩個輸出結果都是:6.

這裡需要幾點說明.shell中是不能直接獲得函式的返回值的,如果你要用函式返回值,只能用全域性變數傳輸。shell中的變數預設都是全域性的,除非你在前面加了local修飾符。如上面的例子,在函式外面,result變數也是可見的。如果你在result前加local修飾,result變數在函式外就不可見了。但shell會把函式返回值放在$?全域性變數中,你可以用$? 來取得前個函式呼叫的返回值。$*可以獲得函式的所有輸入引數,$1表示第一個引數,以此類推。

五.其他

shell內建的一些特徵,可以很容易的處理檔案,以及和其他程式互動。

檔案比較運算子

-e filename 	如果 filename存在,則為真 	[ -e /var/log/syslog ]
-d filename 	如果 filename為目錄,則為真 	[ -d /tmp/mydir ]
-f filename 	如果 filename為常規檔案,則為真 	[ -f /usr/bin/grep ]
-L filename 	如果 filename為符號連結,則為真 	[ -L /usr/bin/grep ]
-r filename 	如果 filename可讀,則為真 	[ -r /var/log/syslog ]
-w filename 	如果 filename可寫,則為真 	[ -w /var/mytmp.txt ]
-x filename 	如果 filename可執行,則為真 	[ -L /usr/bin/grep ]
filename1-nt filename2 	如果 filename1比 filename2新,則為真 	[ /tmp/install/etc/services -nt /etc/services ]
filename1-ot filename2 	如果 filename1比 filename2舊,則為真 	[ /boot/bzImage -ot arch/i386/boot/bzImage ]
 

for 迴圈中很容易遍歷檔案

for file in /home/*
do
   if [ -d "$file" ] 
   then
      echo $file is a directory
    fi
done

很容易呼叫其他程式的輸出結果:

for user in `awk -F":" '{ print $1 }' /etc/passwd`
do
    echo find user $user
done

 shell腳步中要使用其他命令的輸出結果,只需用`符號把命令包含起來。注意:這個符號不是單引號,在鍵盤左上角那個位置。

六. 後記

基本的shell語法就學了這些,高階的還沒弄通。這篇筆記也差不多長了,別的再邊學邊寫。shell是基礎,要配合awk,grep,sed這些工具才能發揮出效果。最近在看《unix程式設計藝術》,上面談到了*nix系統的幾個哲學基礎原則,其中有個原則就是:

組合原則:設計時考慮拼接組合

*nix系統程式的的輸入和輸出一般都是簡單,文字化,面向流的格式。這樣便於程式和程式之間的互動和拼接。*nix系統下的程式一般都只完成單一功能,如果你需要要一個複雜的功能,那就需要把小程式拼接在一起。這一特徵也決定了shell在*uix系統中的重要性。

七.shell學習資料

本文中的許多例子以及資料就是來自該系列教程

Gnu的bash官方參考手冊