本文章從五個方面來介紹linux中shell命令,包括有Shell變數、Shell的基本結構、Shell函數的傳回值、Shell函數詳解 、Shell當中的特殊變數 希望能對初學者有所協助。
Shell入門教程:Shell變數
變數
變數是暫時用來儲存資料的地方,是一個記憶體空間。bash shell和其他的程式設計語言,沒有“資料形態”,也就是說預設情況下不區分一個變數是整型還是浮點型等,除非你使用declare語句申明變數類型。在bash shell中,預設只有一種資料型,就是由字元組成的字串。同時,設定的變數只在當前的shell中存在,也就是,每一個shell都會維護一份他們自己的變數,彼此不會有影響。可以把變數匯出成環境變數,這樣其他的shell就可以被子shell引用。
變數的命名規則:
1.可以使用英文字母、數字和底線組成
2.第一個字元不能是數字
3.區分大小寫
變數設定:
變數名=值
例如:name=john
建議這樣設定變數:name="john" 或者name='john'
在引用變數的時候使用雙引號和單引號是有區別的,單引號不會進行變數替換。而在雙引號中,如果也想抑制變數替換,則需要使用轉義符反斜線
引用變數:
$變數名
建議這樣引用變數:${變數名}
環境變數:
使用下面的任意一個方法可以使name變為環境變數
name="john"
export name
export name="john"
declare -x name="john"
bash的一些重要的內建變數:
$1 ~ $n? 參數位置。當n超過9後,使用${n},例如${10}
$* 代表所有的參數位置,而且視為一個字串
$@ 代表所有的參數位置,但是代表各位置參數組成的串列
$# 參數的個數
$? 上一個命令的傳回值
$! 上一個後台進程的編號
$$ 目前shell的進程編號
Shell的基本結構
shell程式的基本組成結構
shell結構大體是由設定變數、內建命令、shell的文法結構、函數組成。
使用執行個體說明:test.sh
代碼如下 |
複製代碼 |
#!/bin/bash #說明使用/bin/bash作為這個指令碼的解譯器 #定義一個函數 function my_fun () { echo "Hello, $1,today is $2" } #定義連個變數 name=$1 today=`date` #函數調用 my_fun "$name" "$today" |
上面的這個指令碼要想運行還需要做一些操作,首先給予執行許可權
chmod +x test.sh
然後執行
./test.sh john
輸出
Hello, john,today is Tue Jun? 1 14:51:46 CST 2010
父shell和子shell
在執行script之前,身處的環境就是父shell。執行script之時,父shell根據#!/bin/bash,fork出來一個新的shell環境,然後在子shell中執行,執行完畢後子shell結束,任然回到父shell中,這樣不會影響到父shell的環境。
這張圖片是login shell的流程,當是non-login shell時,只執行方框中的標註的部分。由這張圖我們可以知道,在如下幾種情況下,執行的流程。
登陸(login)
/etc/profile
~/.bash_profile
登出(logout)
~/.bash_logout
執行新shell,分成兩種情況
1.執行互動shell
~/.bashrc
/etc/bashrc
2.執行非互動shell,比如執行script會檢查 BASH_ENV 變數的內容,如果有定義,則執行。
Shell函數的傳回值
shell函數傳回值一般有3種方式:
1、return語句(預設的傳回值)
shell函數的傳回值可以和其他語言的傳回值一樣,通過return語句返回。
比如:
代碼如下 |
複製代碼 |
#!/bin/bash function mytest() { echo "mytest function" echo "argv[1] = $1" if [ $1 = "1" ] ;then return 1 else return 0 fi } echo "mytest 1" mytest 1 echo $? echo "mytest 0" mytest 0 echo $? if mytest 1 ; then echo "mytest 1" fi
if mytest 0 ;then echo "mytest 0" fi
echo "end"
|
先定義了一個函數,mytest,它根據輸入的參數是否為1來return 1,否則return 0。
擷取函數的傳回值通過調用函數,或者最後執行的值獲得。
另外,可以直接用函數的傳回值用作if的判斷。
注意:return只能用來返回整數值,且和c的區別是返回為正確,其他的值為錯誤。
2、全域變數或者環境變數
這種就類似於c中的全域變數。
代碼如下 |
複製代碼 |
#!/bin/bash g_var= function mytest2() { echo "mytest2" echo "args $1" g_var=$1 return 0 } mytest2 1 echo "g_var=$g_var" |
函數mytest2通過修改全域變數的值來返回結果。
3、以上兩個方法失效的時候
以上介紹的這兩種方法在一般情況下都是好使的,但也有例外。
比如:
代碼如下 |
複製代碼 |
#!/bin/bash
function mytest3() { grep "123" test.txt | awk -F: '{print $2}' | while read line ;do echo "$line" if [ $line = "yxb" ]; then return 0 fi done echo "mytest3 here " return 1 } g_var=
function mytest4() { grep "123" test.txt | awk -F: '{print $2}' | while read line ;do echo "$line" if [ $line = "yxb" ]; then g_var=0 echo "g_var=0" return 0 fi done echo "mytest4 here " return 1 } mytest3 echo $? mytest4 echo "g_var=$g_var" |
test.txt中的內容如下:
代碼如下 |
複製代碼 |
456:kkk 123:yxb 123:test 輸出如下: yxb@yxb-laptop:~/文檔/個人文檔/shell函數傳回值$ ./no_function.sh yxb mytest3 here 1 yxb g_var=0 mytest4 here g_var= |
可以看到mytest3在return了以後其實沒有直接返回,而是執行了迴圈體後的語句,同時看到mytest4中也是一樣,同時,在mytest4中,對全域變數的修改也無濟於事,全域變數的值根本就沒有改變。
這個是什麼原因那?
筆者認為,之所以return語句沒有直接返回,是因為return語句是在管道中執行的,管道其實是另一個子進程,而return只是從子進程中返回而已,只是while語句結束了,而函數體之後的語句會繼續執行。
同理,全域變數在子進程中進行了修改,但是子進程的修改沒有辦法反應到父進程中,全域變數只是作為一個環境變數傳入子進程,子進程修改自己的環境變數,不會影響到父進程。
因此在寫shell函數的時候,用到管道的時候一定要清楚,此刻是從什麼地方返回。
4、echo傳回值(顯式輸出)
其實在shell中,函數的傳回值有一個非常安全的返回方式,即通過輸出到標準輸出返回。因為子進程會繼承父進程的標準輸出,因此,子進程的輸出也就直接反應到父進程。因此不存在上面提到的由於管道導致傳回值失效的情況。
在外邊只需要擷取函數的傳回值即可。
代碼如下 |
複製代碼 |
#!/bin/bash function mytest5() { grep "123" test.txt | awk -F: '{print $2}' | while read line ;do if [ $line = "yxb" ]; then echo "0" return 0 fi done return 1 } result=$(mytest5) if [ -z $result ]; then echo "no yxb. result is empyt" else echo "have yxb, result is $result" fi |
輸出如下:
view sourceprint?
1 have yxb, result is 0
這個方式雖然好使,但是有一點一定要注意,不能向標準輸出一些不是結果的東西,比如調試資訊,這些資訊可以重新導向到一個檔案中解決,特別要注意的是,用到比如grep這樣的命令的時候,一定要記得 1>/dev/null 2>&1 來避免這些命令的輸出。
echo輸出另一技巧:用函數的傳回值作為另外一個函數的參數
代碼如下 |
複製代碼 |
#!/bin/bash Dir=/cygdrive/d/server/ebin function display() { files=`ls $Dir` echo $files } echo `display` function filetype() { echo `file $Dir/$1` #輸出待檢測檔案的類型 } for file in `display` #調用display函數,對其傳回值做遍曆 do filetype $file #檢測檔案類型並輸出 done
|
小總結:
用 $? 來擷取函數的 return值,用 $(函數名) 來擷取函數的 echo值。
Shell函數詳解
Shell函數類似於Shell指令碼,裡面存放了一系列的指令,不過Shell的函數存在於記憶體,而不是硬碟檔案,所以速度很快,另外,Shell還能對函數進行預先處理,所以函數的啟動比指令碼更快。
1、函數定義
function 函數名() {
語句
[return]
}
關鍵字function表示定義一個函數,可以省略,其後是函數名,有時函數名後可以跟一個括弧,符號“{”表示函數執行命令的入口,該符號也可以在函數名那一行,“}”表示函數體的結束,兩個大括弧之間是函數體。
語句部分可以是任意的Shell命令,也可以調用其他的函數。
如果在函數中使用exit命令,可以退出整個指令碼,通常情況,函數結束之後會返回調用函數的部分繼續執行。
可以使用break語句來中斷函數的執行。
declare –f 可以顯示定義的函數清單
declare –F 可以只顯示定義的函數名
unset –f 可以從Shell記憶體中刪除函數
export –f 將函數輸出給Shell
另外,函數的定義可以放到 .bash_profile 檔案中,也可以放到使用函數的指令碼中,還可以直接放到命令列中,還可以使用內部的unset命令刪除函數。一旦使用者登出,Shell將不再保持這些函數。
2、函數的調用
函數調用的執行個體:
代碼如下 |
複製代碼 |
#!/bin/bash function show() { echo "hello , you are calling the function" } echo "first time call the function" show echo "second time call the function" show |
3、函數參數的傳遞
函數可以通過位置變數傳遞參數。例如
函數名 參數1 參數2 參數3 參數4
當函數執行時,$1 對應 參數1,其他依次類推。
執行個體:
代碼如下 |
複製代碼 |
#!/bin/bash function show() { echo "hello , you are calling the function $1" } echo "first time call the function" show first echo "second time call the function" show second |
4、函數的傳回值
函數中的關鍵字“return”可以放到函數體的任意位置,通常用於返回某些值,Shell在執行到return之後,就停止往下執行,返回到主程式的調用行,return的傳回值只能是0~256之間的一個整數,傳回值將儲存到變數“$?”中。
執行個體:
代碼如下 |
複製代碼 |
#!/bin/bash function abc() { RESULT=`expr $1 % 2` #表示取餘數 if [ $RESULT –ne 0 ] ; then return 0 else return 1 fi } echo "Please enter a number who can devide by 2" read N abc $N case $? in 0) echo "yes ,it is” ;; 1) echo “no ,it isn’t” ;; esac
|
在這裡要注意參數傳遞了,上面read進來的數字,必須加上$符號才能傳遞給函數,我剛開始不知道是哪裡錯了,找了半天才知道是這裡出錯了。
5、函數的載入
如果函數在另外一個檔案中,我們該怎麼調用它呢?
這裡就有一個方法。比如 show 函數寫在了function.sh裡面了,我們就可以用
代碼如下 |
複製代碼 |
source function.sh
|
2 show
這樣就可以調用了。
6、函數的刪除
用法:unset –f 函數名
7、函數的變數範圍
預設情況下,變數具有全域範圍,如果想把它設定為局部範圍,可以在其前加入local
例如:
代碼如下 |
複製代碼 |
local a="hello"
|
使用局部變數,使得函數在執行完畢後,自動釋放變數所佔用的記憶體空間,從而減少系統資源的消耗,在運行大型的程式時,定義和使用局部變數尤為重要。
8、函數的嵌套
函數可以進行嵌套,執行個體:
代碼如下 |
複製代碼 |
#!/bin/bash function first() { function second() { function third() { echo "------this is third" } echo "this is the second" third } echo "this is the first" second } echo "start..." first |
Shell當中的特殊變數
一、保留變數
$IFS 這個變數中儲存了用於分割輸入參數的分割字元,預設識空格。
$HOME 這個變數中儲存了目前使用者的根目錄路徑。
$PATH 這個變數中儲存了當前 Shell 的預設路徑字串。
$PS1 表示第一個系統提示符。
$PS2 表示的二個系統提示符。
$PWD 表示當前工作路徑。
$EDITOR 表示系統的預設編輯器名稱。
$BASH 表示當前 Shell 的路徑字串。
$0, $1, $2, ...
表示系統傳給指令碼程式或指令碼程式傳給函數的第0個、第一個、第二個等參數。
$# 表示指令碼程式的命令參數個數或函數的參數個數。
$$ 表示該指令碼程式的進程號,常用於組建檔案名唯一的臨時檔案。
$? 表示指令碼程式或函數的返回狀態值,正常為 0,否則為非零的錯誤號碼。
$* 表示所有的指令碼參數或函數參數。
$@ 和 $* 涵義相似,但是比 $* 更安全。
$! 表示最近一個在後台啟動並執行進程的進程號。
二、隨機數
隨機數是經常要用到的,BASH 中也提供了這個功能,請看下面這個程式:
代碼如下 |
複製代碼 |
#!/bin/bash # Prints different random integer from 1 to 65536 a=$RANDOM echo $a exit 0 |
這個程式可以在每次執行的時候隨機的列印出一個大小在 1 到 65536 之間的整數。