2017-06-04 41 views
1

鑑於以下bash腳本:看似語義差值

#!/usr/bin/env bash 

echo $BASH_VERSION 

# local [option] [name[=value] ... | - ] 
# For each argument, a local variable named name is created, and assigned value. The option can be any 
# of the options accepted by declare. When local is used within a function, it causes the variable name 
# to have a visible scope restricted to that function and its children. If name is -, the set of shell 
# options is made local to the function in which local is invoked: shell options changed using the set 
# builtin inside the function are restored to their original values when the function returns. With no 
# operands, local writes a list of local variables to the standard output. It is an error to use local 
# when not within a function. The return status is 0 unless local is used outside a function, an invalid 
# name is supplied, or name is a readonly variable. 

function __count_words { 
    local feedback=$(echo "app1 app2") 
    echo $feedback 
    return $(IFS=' ' set -- ${feedback} && echo $#) 
} 

function invoke_func { 
    declare -f $1_${DF_SYSTEM} >/dev/null 
    [ $? -eq 0 ] && { $1_${DF_SYSTEM}; return $?; } || { $1; return $?; } 
} 

function check_words { 
    local list=$(invoke_func __count_words) 
    local count=$? 
    echo "V1: XXXX [c=$count] > $list" 
    list2=$(invoke_func __count_words) 
    local count2=$? 
    echo "V2: XXXX [c=$count2] > $list2" 
} 

check_words 

輸出是:

4.4.12(1)-release 
V1: XXXX [c=0] > app1 app2 
V2: XXXX [c=2] > app1 app2 

什麼決定,使一個看似背後的基本原理類似的賦值語法在返回值方面有所不同?我認爲我找到了bash(1)手冊頁的相關部分,但是爲什麼這樣做是不明確的。

在本地變量賦值的情況下,返回狀態始終爲0,但是對於全局賦值,返回狀態根據賦值中被調用函數的返回狀態而變化。

+0

你錯誤地解釋了這個問題。這不是事實,它是一個本地任務,改變了事情;這是事實上,你將賦值**放在與'local'命令相同的行**上。 –

+2

順便說一句,'IFS =''設置 - $ {feedback} && echo $#'是一個**錯誤的方式來計算單詞 - 如果你的任何單詞擴展爲一個整數,你會得到數字與當前工作目錄中的glob相匹配的結果添加到結果中。使用'IFS =''讀取-r -a數組;回聲「$ {#數組[@]}」'而不是。 –

+0

順便說一句,函數的返回狀態也是返回值的錯誤方式 - 它用於成功/失敗狀態。一個問題是,由於它是一個8位無符號整數,它只能返回0-255範圍內的值。因此,'返回256'實際上會返回0的狀態,'返回257'實際上會返回1,等等。很顯然, –

回答

2

這是Shellcheck檢測爲SC2155的問題;考慮閱讀鏈接的wiki頁面(也許,在將來這裏詢問之前,通過Shellcheck運行你的代碼)。


的最佳做法,實現您的check_words功能是這樣的,而表現出您的問題:

check_words() { 
    local list count count2    # intentionally leaving list2 global 
    list=$(invoke_func __count_words) 
    count=$? 
    echo "V1: XXXX [c=$count] > $list" 
    list2=$(invoke_func __count_words) 
    count2=$? 
    echo "V2: XXXX [c=$count2] > $list2" 
} 

local關鍵字是一個內置的命令。像其他命令一樣,它具有退出狀態。因此,該退出狀態將覆蓋用於派生值的命令替換中的任何退出狀態。 (此外,function關鍵字使您的代碼無償地與POSIX sh不兼容,但不會增加任何補償優勢;最好避免使用符合POSIX的函數聲明語法)。

+1

。感謝超級快速反饋。愛這個社區。 – Moreaki