함수에서 pidof 실행

함수에서 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서브쉘에서 실행하면 서브쉘과 스크립트를 감지하여 결과를 해석할 것이라고 생각합니다 . 하지만 여기서 서브쉘이 어떻게 생성되는지 이해가 안 가나요?

이 문제의 원인은 무엇이며 어떻게 해결할 수 있나요?

답변1

코드에서 처리되지 않은 명령이 실패하면 set -e(약어로 set -o errexit) 셸이 종료됩니다.

pidof일치하는 프로세스를 찾을 수 없으면 실패한 종료 상태가 반환되지만 사용자가 실패를 처리했습니다. pidof다음과 같이 사용됨그리고-또는 목록, 그래서 실제로 실패합니다아니요방아쇠 errexit.

하지만 당신이 사용했기 때문에그리고-또는 목록0이 아닌 종료 상태로 종료되는 if생성자를 사용해야 하는 경우 해당 and-or-list가 함수에서 마지막으로 실행 되기 때문에 함수 자체도 실패한 종료 상태를 반환합니다.pidof && othercommandcheckIfRunningcheckIfRunning

그리고 결함이 처리되지 않아 errexit트리거됩니다. 실패로 인해 errexit발생하는 것이 아니라 실패로 인해 발생합니다.pidofcheckIfRunning

여기에 다음을 작성해야 합니다.

checkIfRunning() {
  if pidof -o %PPID -x -- "$0" >/dev/null; then
    echo >&2 'Already running!'
    exit 1
  fi
}

구성된 종료 상태는 if또는 섹션에서 실행된 마지막 명령의 종료 상태이거나, 실행된 명령이 없는 경우 조건 섹션의 종료 상태입니다.thenelse0

일반적으로 ifand-or 목록 대체 구조는 다음과 같습니다.잘못된. 전반적인 종료 상태 문제 외에도 스크립트 echo가 실패 하면 pidof && echo && exit 1스크립트가 종료되지 않습니다 .

errexit나는 이것을 피해야 하며 함수나 가장 간단한 스크립트 이외의 다른 것을 사용하면 적절한 오류 처리를 수행해야 한다고 생각합니다.

바라보다set -euo pipefailBash 위키의 해당 섹션(의 약어 set -o errexit -o nounset -o pipefail) 또는이 FAQ 항목.

~에 대한귀하의 (현재 삭제된) 답변이 문제를 해결하려고 시도합니다.

checkIfRunning() {
  set +e                              # <---
  pidof -o %PPID -x $0 >/dev/null \
    && echo "running!" && exit 1
  set -e                              # <---
}

작동하는 유일한 이유는 set -e성공 상태로 종료되기 때문입니다. 따라서 이 checkIfRunning역시 set +e관련성이 없고 불필요하며 or set -e로 대체될 수 있습니다 .truereturn 0

관련 정보