쉘 스크립트가 잠자고 있는 동안 외부에서 어떻게 제어할 수 있습니까?

쉘 스크립트가 잠자고 있는 동안 외부에서 어떻게 제어할 수 있습니까?

저는 쉘 스크립팅을 처음 접했습니다. 다음과 비슷한 스크립트가 있습니다.

while [ true ]
do
  sleep 5m
  # PART X: code that executes every 5 mins
done

실행 중인 동안 (1) 외부에서 프로그램을 가로채고 (2) 잠자는 프로세스를 중지하고 즉시 파트 X를 실행할 수 있는 방법은 무엇입니까? 이를 달성하기 위해 SIGNALS를 사용할 수 있습니까? 아니면 더 좋은 방법이 있나요?

이런 종류의 문제를 해결하는 일반적인 방향을 알려 주시겠습니까?

답변1

처리 시간은 스크립트의 책임입니다. 비록 이것이 오늘 사용하기 위한 것이라 하더라도 /bin/sleep미래에는 사용되지 않을 수 있으므로 실제로 장기적으로 작동한다는 보장은 없습니다. 알았어 네가 보고 싶어할 수 있는그러한 보증을 하되 하지 않는 것이 좋습니다. 내 요점은 sleep이 구현 세부 사항이므로 스크립트 외부에서 직접 sleep을 종료해서는 안 된다는 것입니다. 대신 스크립트가 다른 신호를 포착하여 SIGUSR1스크립트로 보내도록 하십시오.

간단한 예는 다음과 같습니다.

#!/usr/bin/env bash

kill_the_sleeper () {
    # This probably isn't really needed here
    # If we don't kill the sleep process, it'll just
    # hang around in the background until it finishes on its own
    # which isn't much of an issue for "sleep" in particular
    # But cleaning up after ourselves is good practice, so let's
    # Just in case we end up doing something more complicated in future
    if [ -v sleep_pid ]; then
        kill "$sleep_pid"
    fi
}

trap kill_the_sleeper USR1 EXIT

while true; do
    # Signals don't interrupt foreground jobs,
    # but they do interrupt "wait"
    # so we "sleep" as a background job
    sleep 5m &
    # We remember its PID so we can clean it up
    sleep_pid="$!"
    # Wait for the sleep to finish or someone to interrupt us
    wait
    # At this point, the sleep process is dead (either it finished, or we killed it)
    unset sleep_pid

    # PART X: code that executes every 5 mins
done

그러면 당신은 원인이 될 수 있습니다10부달리 kill -USR1 "$pid_of_the_script"거나pkill -USR1 -f my_fancy_script

이 스크립트는완벽한어쨌든, 하지만 최소한 간단한 경우에는 좋을 것입니다.

답변2

다른 터미널에서 프로세스
를 종료합니다 sleep.

pkill -f "sleep 5m"

주기는 계속됩니다.


pkill운영 체제에서 사용할 수 없는 경우 다음을 사용하여 PID를 얻을 수 있습니다.

$ ps aux | grep '[s]leep'
username 14628  0.0  0.0   8816   672 pts/19   S+   08:33   0:00 sleep 5m

그런 다음 kill PID프로세스를 종료하십시오(여기 kill 14628: ).


이는 수동으로 종료하는 데 유용 하지만 일반적으로 스크립트를 사용하는 경우 명령의 모든 프로세스를 sleep종료하므로 좋은 솔루션이 아닐 수 있습니다 .sleep 5m


스크립트를 편집할 수 있는 경우 더 안전한 옵션은 다음과 같습니다.

PID를 파일에 쓰도록 스크립트를 변경하십시오.

TMP_DIR="$HOME/.cache/myscript/"
mkdir -p "$TMP_DIR"
while [ true ]
do
  sleep 5m &
  printf '%s' $! > "$TMP_DIR"/sleep.PID
  wait
  # PART X: code that executes every 5 mins
done

그런 다음 다음을 실행할 수 있습니다.

kill $(< ~/.cache/myscript/sleep.PID)

예를 들어 동일한 스크립트의 다른 인스턴스가 PID 파일을 덮어쓸 수 있으며 요구 사항에 비해 충분히 안정적이지 않을 수 있습니다.

답변3

@sitaram이 사용하는 방식이 마음에 듭니다 ionotifywait. 그러나 보다 일반적인 인프라, 즉 셸 read명령(Bash/ksh/Zsh에서 선택적 시간 제한 포함) 및 FIFO를 사용하여 비슷한 작업을 수행할 수 있습니다 .

대기 루프는 다음과 같습니다.

mkfifo /tmp/myfifo
while true; do
    read -t $((5*60)) <> /tmp/myfifo
    date
    echo "Executed every 5 minutes"
done

읽기를 조기에 중단하려면 FIFO에 개행 문자를 쓰기만 하면 됩니다.

echo > /tmp/myfifo

몇 가지 참고사항:

  1. <>일반 대신 비차단 리디렉션을 사용하세요 <. Bash의 일반 리디렉션 블록(FIFO가 기록될 때까지) Bash가 시작되기 전 read이므로 FIFO가 기록되지 않으면 시간 초과가 발생하지 않습니다.
  2. while [ true ]문자열 "true"가 비어 있지 않은지 테스트하고, 비어 있지 않으면 while 루프를 계속합니다. 그러나 이는 추측할 수 있듯이 명령을 실행하면 항상 true를 반환하고, true인 경우 while 루프를 계속한다는 while true의미입니다 . true이 경우 결과는 정확히 동일합니다. 그래도 테스트 구조가 없으면 더 명확할 것 같아요 [ ]. while [ false ]함께 가는 것을 고려해 보세요 while false...
  3. $((5*60))산술 확장입니다. 300사용하기 쉽지만 명령줄에서 산술 연산을 쉽게 수행하는 방법을 보여주는 데 도움이 됩니다.

답변4

가장 쉬운 방법은 특정 파일이 존재하는지 스크립트를 확인하는 것입니다. 그런 다음 while 문에서 더 짧은 간격으로 여러 번 잠을 자십시오. 초를 짧은 간격으로 사용하는 경우 300회(= 5분) 실행되는 for 루프를 사용하게 됩니다. 의사코드: for x=1 to 300 sleep 1 Second check_if_certain_file_exists did 외부적으로는 언제든지 파일을 생성할 수 있으며 스크립트는 1초 간격으로 이를 알아차립니다. 또한 다양한 콘텐츠로 파일을 생성하고 해당 콘텐츠에 따라 스크립트가 다양한 작업을 수행하도록 할 수도 있습니다.

관련 정보