Bash

有條件地將變數設置為只讀的函式

  • April 16, 2019

如果我有一個腳本將變數只讀設置為一些奇數值,並且errexit由於其他不安全的操作而設置:

#!/bin/bash
set -e 
declare -r NOTIFY=$(case "$OS" in (macosx) echo macos_notify ;; (linux) echo linux_notify ;; (*) echo : ;; esac)
declare -r SAY=_say # _say is a function
declare -r VERSION=0.99
set +e 

我第二次使用它來獲取定義,因為它正在開發中:

$ . s.bash 

$ . s.bash 
bash: declare: NOTIFY: readonly variable
Exited

通常declare -r EXISTING_VAR既不會停止腳本也不會刪除EXISTING_VAR.

但是對於errexit,分配給現有變數是可以理解的失敗。簡單的選項是刪除-r或使用set +e該部分腳本。

除此之外,如果名稱已經存在,是否可以編寫一個 Bash 函式來代替declare -r但不重新分配

我試過:

# arg #1: var name, #2: value
set_var_once () {
 # test whether the variable with the 
 # name stored in $1 exists 
 if [[ -z "${!1}" ]] 
 then # if it doesn't, set it
   declare -r $1=$2
 fi
}

我也嘗試過類似的東西eval "declare -r $1=$(eval $2)",感覺eval這裡的某個地方需要,但我不確定在哪裡。

所有版本的set_var_once結果都沒有設置他們應該設置的變數。

declare -r使變數只讀,但也在目前範圍內聲明它,因此使其成為目前函式的本地變數。相反,您只希望readonly前者:

readonly_once() {
 local __assign
 for __assign do
   [[ -v ${__assign%%=*} ]] || readonly "$__assign"
 done
}

用作:

readonly_once VAR1=foo VAR2="$(cmd)" PATH ...

請注意,由於與 相反readonly,thatreadonly_once不是關鍵字(是的,即使隱藏了該事實也是關鍵字),因此readonly需要引用以防止拆分 + glob,此時它不是賦值。bash``$(cmd)

$(cmd)將被擴展(並因此cmd執行),即使該值最終不會被分配(VAR2如果它已經定義)。

該函式僅適用於標量變數,不適用於數組或關聯數組。

引用自:https://unix.stackexchange.com/questions/478515