語境
在設定基本單元測驗系統時,我遇到了一個奇怪的問題。我的目標是確保所有單獨的測驗腳本:
- 運行
set -e以檢測錯誤,而無需在每個檔案中明確設定; - 立即知道要測驗的功能(存盤在另一個檔案中),而無需在每個測驗檔案中顯式獲取這些功能。
觀察
假設這是一個名為to-be-sourced.sh. 我們希望能夠知道其中的命令是否失敗:
# Failing command!
false
# Last command is OK:
true
這是一個虛擬測驗運行器,它必須運行測驗檔案:
#! /usr/bin/env bash
if (
set -e
. to-be-sourced.sh
)
then
echo 'Via set: =0'
else
echo 'Via set: ≠0'
fi
這會產生Via set: =0,這意味著跑步者很開心。但它不應該!我的假設是:
set -eis not propagated within.sourcing, and as explained in the help for.andsource, the exit status is the one of the last command.
But then I came up with a workaround that works, but also relies on .:
if bash -ec '. "$0"' to-be-sourced.sh
then
echo 'Via bash: =0'
else
echo 'Via bash: ≠0'
fi
This yields ≠0 whenever a command in the test file fails, regardless of whether that command was the last one of the test file. As a bonus, I can toss any number of . a/library/file.sh within the -c command, so each test file can use all of my functions out of the box. I should therefore be happy, but:
Why does this work, considering that the -c command also relies on . to load the test file (and I thought bash’s -e was equivalent to set’s -e)?
I also thought about using bash’s --init-file, but it appeared to be skipped when a script is passed as a parameter. And anyway my question is not so much about what I was trying to achieve, but rather about the observed difference of behavior.
Edit
Sounds like if is tempering with the way set -e is handled.
This halts execution, indicating failure:
. to-be-sourced.sh
… while this goes into the then (not the else), indicating success:
if . to-be-sourced.sh
then
echo =0
else
echo ≠0
fi
uj5u.com熱心網友回復:
(這可能并不完全正確,但我認為它捕捉到了發生的事情。)
在您的第一個示例中,在陳述句范圍內的詞法set -e命令中設定選項,因此即使設定了它,它也會被忽略。(您可以通過運行inside來確認它是否已設定。同樣請注意,它本身具有 0 退出狀態,您可以通過替換陳述句來確認它;不是它失敗而是忽略了失敗。)ifecho $-to-be-sourced.sh.trueecho
在您的第二個示例中,在新行程-e中設定選項,該行程對陳述句一無所知,因此不會被忽略。errexitif
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/451504.html
標籤:bash
