
我有一個函數,想使用pipefail
裡面的選項。但我不想簡單地這樣做set -o pipefail
,因為我擔心腳本的另一部分可能不會pipefail
被設定。當然我可以set +o pipefail
稍後再做,但如果pipefail
設定在我的函數之外,這也可能會引入意外的行為。
當然,如果設定了,我可以使用退出代碼false | true
作為衡量標準pipefail
,但這似乎有點髒。
是否有更通用(也許規範?)的方法來檢查設定的 bash 選項?
答案1
在bash-4.4
以上內容中,您可以使用:
myfunction() {
local -
set -o someoption
...
}
一些注意事項:
- 這是從 複製的
ash
。在 中ash
,想法是使$-
(儲存選項集)本地化。它起作用是ash
因為 inash
,local
不會影響變數的值或屬性(與bash
它最初取消設定的位置相反)。儘管如此,它也以與特殊情況bash
相同的方式工作ash
,也就是說,它不會導致$-
被取消設定或恢復為預設行為 - 它僅涵蓋使用 設定的選項
set -o option
,而不涵蓋使用 設定的選項shopt -s option
(bash
是唯一具有兩組選項的 shell!) 與局部變數一樣,它是動態作用域,而不是靜態的。
$-
從函數返回時,的值將被恢復,但新設定將影響函數呼叫的其他函數或來源腳本。如果您想要靜態作用域,則需要切換到 ksh93 並使用:function myfunction { set -o myoption ... other_function }
other_function
只要它function other_function {
也是用語法(而不是 Bourneother_function()...
語法)聲明的,就不受影響。由於它不會重置選項,因此您的函數可能仍會受到其他程式碼設定的選項的影響。為了避免這種情況,您需要使用
zsh
它。zsh
相當於local -
isset -o localoptions
,但你也可以得到一個眾所周知的模擬模式本地。例如:myfunction() { emulate -L zsh set -o someoption ... }
將以一組合理的 zsh-default 選項開始(有一些例外,請參閱文件),在其上新增您的選項。這也是像 ash/bash 中那樣的動態作用域,但您也可以使用以下方式呼叫其他函數:
emulate zsh -c 'other_function...'
other_function
以便使用普通 zsh 選項集來呼叫它。zsh 還有許多運算符,可讓您避免首先全域變更選項(例如
(N)
/用於/ 的glob(D)
限定符,用於不區分大小寫的通配符的 glob 運算符,以避免與,混合)nullglob
dotglob
(#i)
${(s:x:)var}
$IFS
${~var}
要求在參數擴展時進行通配(您需要noglob
在其他類似 Bourne 的 shell 中避免(!) 它)...
答案2
此$SHELLOPTS
變數保存所有用冒號分隔的設定選項。例如,它可能看起來像:
braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor
要檢查給定選項,可以執行以下操作:
# check if pipefail is set, if not set it and remember this
if [[ ! "$SHELLOPTS" =~ "pipefail" ]]; then
set -o pipefail;
PIPEFAIL=0;
else
PIPEFAIL=1;
fi
# do something here
# reset pipefail, if it was not set before
if [ "$PIPEFAIL" -eq 0 ]; then
set +o pipefail;
fi
答案3
如果您想在函數內設定 shell 選項,但又不想影響呼叫者,可以透過兩種不同的方式進行:
選項 1:子 shell
將函數放入子 shell 中(請注意函數語句周圍的括號而不是大括號):
function foo() (
set -o pipefail
echo inside foo
shopt -o pipefail
# ...
)
然後,呼叫者可以取消設定 pipelinefail 並且不受影響:
$ shopt -o pipefail
pipefail off
$ foo
inside foo
pipefail on
$ shopt -o pipefail
pipefail off
或者
選項 2:測試和重置
您可以根據需要測試並重設該選項(請注意函數語句周圍的花括號—沒有子 shell):
function foo() {
shopt -q -o pipefail
local resetpipefail=$?
set -o pipefail
echo inside foo
shopt -o pipefail
# ...
# only reset pipefail if needed
[[ $resetpipefail -eq 1 ]] && set +o pipefail
}
$ shopt -o pipefail
pipefail off
$ foo
inside foo
pipefail on
$ shopt -o pipefail
pipefail off
帽子提示庫恩勒姆他們的shopt -q
回答。
答案4
使用 RETURN 陷阱
使用陷阱指定的命令在使用或傳回
RETURN
執行的 shell 函數或 shell 腳本還原之前執行。.
source
[...]
選項-p
[to shopt] 使輸出以可重複用作輸入的形式顯示。
foo() {
trap "$(shopt -p -o pipefail)" RETURN
set -o pipefail
echo inside foo
shopt -o pipefail
# ...
}
測試
$ shopt -o pipefail
pipefail off
$ foo
inside foo
pipefail on
$ shopt -o pipefail
pipefail off
以下函數範本處理一般情況,確保函數在返回時set
和shopt
選項都恢復為其原始值:
foo() {
trap "$(shopt -p -o; shopt -p)" RETURN # ①
# ...
}
①shopt -p -o
可簡化為標準等效set +o
。