/tmp
호출 디렉터리 에 파일이 나타날 때까지 기다리는 쉘 스크립트를 작성하려고 합니다. sleep.txt
파일이 발견되면 프로그램이 중지됩니다. 그렇지 않으면 파일을 찾을 때까지 프로그램이 잠자기 상태(중지)가 되도록 하고 싶습니다. 이제 test 명령을 사용한다고 가정하겠습니다. 그처럼
(if [ -f "/tmp/sleep.txt" ];
then stop
else sleep.)
저는 쉘 스크립트 작성이 처음인데 도움을 주시면 대단히 감사하겠습니다!
답변1
Linux에서는 다음을 사용할 수 있습니다.inotify커널 하위 시스템은 디렉터리에 파일이 있을 때까지 효과적으로 기다립니다.
inotifywait -e create,moved_to,attrib --include '/sleep.txt$' -qq /tmp
# script execution continues ...
참고: 파일이 이미 존재하는 경우에도 등록되도록 attrib
이벤트를 추가했습니다 .touch /tmp/sleep.txt
sleep.txt가 다음과 같이 표시되는 경우inotify기다려즉, 시계가 빌드되기 전에 파일이 생성되거나 터치될 수 있고 이후에는 다시는 호출되지 않는 경우 다음과 같이 코드를 확장할 수 있습니다.
coproc inw {
LC_ALL=C inotifywait -e create,moved_to --include '/sleep.txt$' /tmp 2>&1
}
while IFS= read -r -u "${inw[0]}" line; do
if [ "$line" = "Watches established." ]; then
break
fi
done
if [ -f /tmp/sleep.txt ]; then
kill $inw_PID
else
wait
fi
# script execution continues ...
고정 간격 폴링과 비교한 이 접근 방식의 장점
while [ ! -f /tmp/sleep.txt ]; do sleep 1; done
# script execution continues ...
더 많이자는 것은 당신의 과정입니다. inotify 이벤트 사양(예: 스크립트)을 사용하여 create,attrib
다음 파일이 생성되거나 열릴 때만 실행되도록 예약합니다. /tmp
고정된 간격으로 폴링하면 시간이 증가할 때마다 CPU 주기가 낭비됩니다.
답변2
테스트를 while
루프에 넣어보세요.
while [ ! -f /tmp/sleep.txt ]; do sleep 1; done
# next command
답변3
inotifywait
지금까지 제공된 일부 기반 방법에는 몇 가지 문제가 있습니다.
sleep.txt
먼저 임시 이름으로 생성된 후 로 이름이 변경된 것을 찾을 수 없습니다sleep.txt
.moved_to
다음 외에도 일치하는 이벤트가 필요합니다.create
sleep.txt
파일 이름에는 개행 문자가 포함될 수 있으며, 개행으로 구분된 파일 이름을 인쇄하는 것만으로는 해당 파일이 생성되었는지 여부를 확인할 수 없습니다 .foo\nsleep.txt\nbar
예를 들어 파일이 생성되면 어떻게 될까요?- 파일이 이미 생성된 경우 수행할 작업앞으로
inotifywait
시계의 전원을 켜고 설치했습니까? 그런 다음inotifywait
이미 존재하는 파일을 영원히 기다립니다. 파일이 이미 존재하지 않는지 확인해야 합니다.뒤쪽에시계가 설치되었습니다. inotifywait
일부 솔루션은 파일을 찾은 후에도 계속됩니다(적어도 다른 파일이 생성될 때까지).
이러한 문제를 해결하려면 다음을 수행할 수 있습니다.
sh -c 'echo "$$" &&
LC_ALL=C exec inotifywait -me create,moved_to --format=/%f/ . 2>&1' | {
IFS= read pid &&
while IFS= read -r line && [ "$line" != "Watches established." ]; do
: wait for watches to be established
done
[ -e sleep.txt ] || [ -L sleep.txt ] || grep -qxF /sleep.txt/ && kill "$pid"
}
sleep.txt
현재 디렉터리에서 생성을 모니터링하고 있다는 점에 유의하세요. 따라서 예제에서는 이전 작업을 수행해야 합니다 .
. cd /tmp || exit
현재 디렉터리는 절대 변경되지 않으므로 이 파이프가 성공적으로 반환되면 sleep.txt
생성된 현재 디렉터리가 됩니다.
물론 위와 .
같이 바꿀 수 있지만 런타임 시 이름이 여러 번 바뀌거나(가능성은 낮지 만 일반적인 경우 고려해야 할 사항) 그 위에 새 파일 시스템이 마운트되었을 수 있으므로 파이프가 반환될 때 그렇지 않을 수도 있습니다. 창조된 것이 되되 하나는 . 이 시간 동안 새 디렉터리가 생성되었고 해당 디렉터리가 모니터링되지 않아 거기에 생성된 디렉터리가 감지되지 않을 수도 있습니다 ./tmp
inotifywait
/tmp
/tmp
/tmp/sleep.txt
/new-name-for-the-original-tmp/sleep.txt
/tmp
sleep.txt
답변4
maxschlepzig의 허용된 답변(및 허용된 답변의 아이디어)을 기반으로 합니다.https://superuser.com/questions/270529/monitoring-a-file-until-a-string-is-found) 나는 시간 초과에도 작동하는 다음과 같은 향상된 (내 의견으로는) 답변을 제안합니다.
# Enable pipefail, so if the left side of the pipe fails it does not get silently ignored
set -o pipefail
( timeout 120 inotifywait -e create,open --format '%f' --quiet /tmp --monitor & ) | while read i; do if [ "$i" == 'sleep.txt' ]; then break; fi; done
EXIT_STATUS=$?
if [ "${EXIT_STATUS}" == '124' ]; then
echo "Timeout happened"
fi
지정된 시간 초과 내에 파일이 생성/열리지 않으면 종료 상태는 124입니다(시간 초과 문서(man 페이지)에 따라). 생성/열린 경우 종료 상태는 0(성공)입니다.
예, inotifywait는 이런 방식으로 하위 쉘에서 실행되며 하위 쉘은 시간 초과가 발생하거나 기본 스크립트가 종료되는 경우에만 실행이 완료됩니다.