Linux中Shell入門教程

來源:互聯網
上載者:User

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 之間的整數。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.