Bash

在函式中執行 pidof

  • July 16, 2022

我想檢測我的腳本是否已經在執行,所以我使用這個

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構造的退出狀態是在thenorelse部分中執行的最後一個命令的退出狀態,或者0如果沒有執行,則不是條件部分的退出狀態。

通常,用ifand-or 列表替換結構是錯誤的。除了整體退出狀態的問題,如果echo你的 失敗pidof && echo && exit 1,腳本不會退出。

我認為,一旦您使用函式或除了最簡單的腳本之外的任何其他東西,就errexit應該避免並進行適當的錯誤處理。

請參閱bash wiki(縮寫)或此 FAQ 條目中的相應部分set -euo pipefailset -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可以替換為trueor return 0

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