在函式中執行 pidof
我想檢測我的腳本是否已經在執行,所以我使用這個:
pidof -o %PPID -x "$0" >/dev/null && echo 'already running!' && exit 1
這樣可行。但我希望它在一個函式中:
#!bin/bash set -eu set -o pipefail checkIfRunning() { pidof -o %PPID -x "$0" >/dev/null && echo 'already running!' && exit 1 } #... checkIfRunning
這不起作用:即使只有一個腳本實例正在執行,它也總是退出。
我認為如果
pidof
在子shell中執行它會檢測子shell和腳本,從而解釋結果 - 但我看不到這裡是如何創建子shell的?這是什麼原因,我該如何解決?
在您的程式碼中
set -e
(縮寫為set -o errexit
)未處理的命令失敗會導致 shell 退出。
pidof
當沒有找到匹配的程序時返回失敗退出狀態,但您確實處理了該失敗。pidof
用作and-or list的一部分,因此它的失敗不會觸發errexit
。但是,因為您在應該使用構造的地方使用了一個與-或列表,所以它本身以非零退出狀態退出,並且因為該與-或列表是函式中執行的最後一件事,所以函式本身也將返回失敗退出狀態。
if``pidof && othercommand``checkIfRunning``checkIfRunning
並且該故障未被處理,因此
errexit
被觸發。errexit
不是因為pidof
失敗而是因為checkIfRunning
失敗而觸發。在這裡,你應該寫:
checkIfRunning() { if pidof -o %PPID -x -- "$0" >/dev/null; then echo >&2 'Already running!' exit 1 fi }
if
構造的退出狀態是在then
orelse
部分中執行的最後一個命令的退出狀態,或者0
如果沒有執行,則不是條件部分的退出狀態。通常,用
if
and-or 列表替換結構是錯誤的。除了整體退出狀態的問題,如果echo
你的 失敗pidof && echo && exit 1
,腳本不會退出。我認為,一旦您使用函式或除了最簡單的腳本之外的任何其他東西,就
errexit
應該避免並進行適當的錯誤處理。請參閱bash wiki(縮寫)或此 FAQ 條目中的相應部分
set -euo pipefail
。set -o errexit -o nounset -o pipefail
關於您(現已刪除)試圖解決問題的答案:
checkIfRunning() { set +e # <--- pidof -o %PPID -x $0 >/dev/null \ && echo "running!" && exit 1 set -e # <--- }
它起作用的唯一原因是因為
set -e
碰巧以成功狀態退出,所以checkIfRunning
也是如此,不set +e
相關且不需要,set -e
可以替換為true
orreturn 0
。