1. 程式人生 > >shell指令碼中的函式與子shell

shell指令碼中的函式與子shell

shell指令碼中的函式與子shell

原文https://www.jianshu.com/p/7db79d7997b5

函式

函式的使用

bash中也有函式。一個函式就是一個子程式,是用於實現一串操作的程式碼塊。bash中的函式的形式如下:

function function_name(){
  
}

function_name(){
  
}

function_name()
{
  
}

以上三種形式的函式均可達到目的。

使用函式的時候只要簡單的使用函式的名字即可。

例如:

#!/bin/bash 

function abc(){
  echo abc
}

abc

其輸出結果為:

abc

bash中的函式必須在其第一次呼叫之前被完成。沒有如c語言中那種函式宣告的形式。即使提前定義了函式的變數也不可以。但是隻要執行順序中,函式的定義在函式的使用之前即可。

考慮如下情況:

function f1(){
  echo abc
  f2
}

function f2(){
  echo cde
}

f1

這種情況中,雖然看起來f2的使用在其定義之前已經有過一次了,但是實際運行當中我們不難發現f2先定義了之後f1才呼叫了f2。因此這種情況也是可以的。

函式是可以巢狀的。

考慮如下情況:

f1(){
  f2(){
    echo abc
    }
}

f2
f1
f2

其輸出結果類似於:

bash: f2: command not found

abc

第一行表示沒有找到f2,第二行執行了f1,第三行找到了f2。

函式宣告也可能出現在任何看起來不可能的應該有一個命令出現的地方。

由以上內容可以看出,其實函式的定義其實只是一種命令。而bash指令碼是一種線性執行的語言。因此只要保證函式使用的流程正確,就可以將函式應用在各種可能的地方。

函式的傳參

bash的函式能夠接受引數並返回狀態退出碼。

函式以位置來引用傳遞來的引數,類似指令碼的引數傳遞。例如$1,$2等等。

例如:

function abc(){
  echo $1
  return 22
}

abc cde
echo $?

以上內容為一個最簡單的函式的傳參及返回值的情況。

輸出為:

cde
22

此外,shift命令也可以應用於傳遞給函式的引數,像工作在指令碼的引數中那樣。

函式接受引數通常只是接受引數的值。因此我們也可以傳遞間接引用給函式。

例如:

function echoabc(){
  echo $1
}

a=b
b=c

echoabc ${a}
echoabc ${!a}

b=d

echoabc ${a}
echoabc ${!a} 

以上內容的輸出為:

b
c
b
d

與此同理,我們可以在函式中修改間接引用中的值:

#!/bin/bash

function changeabc(){
  echo $1
  eval "echo \$$1"
  eval "$1=xyz"
  eval "echo \$$1"
}

var1=var2
var2=abc

changeabc $var1
echo $var2
eval "echo \$$var1"

以上內容的輸出為:

var2
abc
xyz
xyz
xyz

函式的退出碼

函式返回一個被稱為退出狀態的值. 退出狀態可以由return來指定statement, 否則函式的退出狀態是函式最後一個執行命令的退出狀態(0表示成功,非0表示出錯程式碼). 退出狀態(exit status)可以在指令碼中由$? 引用. 這個機制使指令碼函式也可以像C函式一樣有一個"返回值".

可以用來返回異常狀態。

函式的重定向

函式的本質也是一個程式碼塊,因此我們可以重定向其標準輸入輸出。

例如:

function echoabc(){
    read line
    while [ -n "$line" ]
    do
        echo $line
        read line
    done
} << strings
abcd
cdef
strings

echoabc

將一個heredocuments重定向到函式echoabc的輸入。輸出為:

abcd
cdef

子shell

執行一個shell指令碼時會啟動另一個命令直譯器. 就好像你的命令是在命令列提示下被解釋的一樣, 類似於批處理檔案裡的一系列命令.每個shell指令碼有效地執行在父shell(parent shell)的一個子程序裡.這個父shell是指在一個控制終端或在一個xterm視窗中給你命令指示符的程序.

shell指令碼也能啟動他自已的子程序. 這些子shell(即子程序)使指令碼並行地,有效率地地同時執行多個子任務.

圓括號執行子shell

嵌在圓括號裡的一列命令在一個子shell裡執行。

例如:

(
echo abcd
echo cdef
)

輸出為:

abcd
cdef

在子shell裡的變數不能被這段子shell程式碼塊之外外面的指令碼訪問.這些變數是不能被產生這個子shell的父程序(parent process)存取的,實際上它們是區域性變數(local variables).

例如:

(a=b)
echo $a

輸出為空

在子shell中的目錄更改不會影響到父shell.

子shell可用於為一組命令設定臨時的環境變數

程序在不同的子shell中可以並行地執行.這樣就允許把一個複雜的任務分成幾個小的子問題來同時地處理。

管道產生子shell

管道(|)也會產生子shell。在子shell中可以讀取父shell中的變數,但是不能寫這些變數。有時我們可以通過重定向輸入輸出的方式來傳遞這些變數。詳細的可以參考I/O重定向



作者:Fengya
連結:https://www.jianshu.com/p/7db79d7997b5
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。