저는 쉘 스크립팅을 처음 접했습니다. 다음과 비슷한 스크립트가 있습니다.
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
몇 가지 참고사항:
<>
일반 대신 비차단 리디렉션을 사용하세요<
. Bash의 일반 리디렉션 블록(FIFO가 기록될 때까지) Bash가 시작되기 전read
이므로 FIFO가 기록되지 않으면 시간 초과가 발생하지 않습니다.while [ true ]
문자열 "true"가 비어 있지 않은지 테스트하고, 비어 있지 않으면 while 루프를 계속합니다. 그러나 이는 추측할 수 있듯이 명령을 실행하면 항상 true를 반환하고, true인 경우 while 루프를 계속한다는while true
의미입니다 .true
이 경우 결과는 정확히 동일합니다. 그래도 테스트 구조가 없으면 더 명확할 것 같아요[ ]
.while [ false ]
함께 가는 것을 고려해 보세요while false
...$((5*60))
산술 확장입니다.300
사용하기 쉽지만 명령줄에서 산술 연산을 쉽게 수행하는 방법을 보여주는 데 도움이 됩니다.
답변4
가장 쉬운 방법은 특정 파일이 존재하는지 스크립트를 확인하는 것입니다. 그런 다음 while 문에서 더 짧은 간격으로 여러 번 잠을 자십시오. 초를 짧은 간격으로 사용하는 경우 300회(= 5분) 실행되는 for 루프를 사용하게 됩니다. 의사코드: for x=1 to 300 sleep 1 Second check_if_certain_file_exists did 외부적으로는 언제든지 파일을 생성할 수 있으며 스크립트는 1초 간격으로 이를 알아차립니다. 또한 다양한 콘텐츠로 파일을 생성하고 해당 콘텐츠에 따라 스크립트가 다양한 작업을 수행하도록 할 수도 있습니다.