를 통과하는 서비스가 있습니다 rsync
. 이런 일이 발생하면 서버 측 프로그램의 실행을 트리거하고 싶습니다.
이 명령 덕분에 inotifywait
파일이나 디렉터리의 변경 사항을 모니터링하는 것이 매우 쉽습니다. 하지만 난 알림을 받고 싶어버스트를 한 번만 수정하세요., 업로드 후 프로세스가 무겁고 수정된 모든 파일에 대해 이를 수행하고 싶지 않기 때문입니다.
이벤트 타임스탬프를 기반으로 몇 가지 해킹을 생각해 내는 것은 큰 노력이 아닐 것입니다... 그러나 저는 이것이 상당히 일반적인 문제라고 믿습니다. 그러나 나는 유용한 것을 찾을 수 없었습니다.
갑작스러운 문제를 해결할 수 있는 기발한 명령이 있나요? 나는 다음과 같이 사용할 수 있는 것을 생각하고 있습니다.
inotifywait -m "$dir" $opts | detect_burst --execute "$post_upload"
답변1
자신의 답변에 따라 쉘을 사용하려는 경우 시간 초과 시 반환 코드를 >128로 설정하는 시간 초과 옵션을 read
활용할 수 있습니다 . -t
예를 들어 burst
스크립트는 대략적으로 다음과 같을 수 있습니다.
interval=$1; shift
while :
do if read -t $interval
then echo "$REPLY" # not timeout
else [ $? -lt 128 ] && exit # eof
"$@"
read || exit # blocking read infinite timeout
echo "$REPLY"
fi
done
처음에 버스트의 끝을 감지하지 않으려면 초기 차단 읽기부터 시작하는 것이 좋습니다.
답변2
OP가 여기에 있습니다.
내가 생각해낸 해결책은 다음과 같은 프로그램입니다 burst
.
inotifywait -e moved_to "$monitored_dir" -m \
| burst 2 'echo run post-upload'
스크립트 burst
:
#!/bin/bash
help() {
>&2 echo "Usage: $0 <interval> <command>"
}
set -e
trap help EXIT
interval=${1:?missing interval}; shift
: ${1:?missing command}
trap - EXIT
set +e
exec 3> >(sed "s/^/burst: /" >&2)
while read line; do
echo "$line" >&3
test -n "$!" && kill -term $! 2>/dev/null
(sleep $interval && $SHELL -c "$*") &
done
기본적으로 이는 실제 명령( )을 실행하기 전에 정의된 시간 동안 기다리는 하위 쉘을 생성합니다 (sleep $interval && $SHELL -c "$*")
. 새로 읽은 줄은 inotifywait
해당 쉘(존재하는 경우)을 종료하고 다시 생성합니다.
일련의 행이 끝나면 쉘이 종료되고 sleep
명령이 실행됩니다.
몇 가지 단점이 있습니다:
stdin의 각 줄에 대한 프로세스를 종료하고 생성합니다. 이는 먼저 행 수를 줄이고 싶다는 의미입니다(따라서
-e moved_to
필터inotifywait
). 업로드된 파일의 수가 너무 많으면, WRT 성능을 감당할 수 없습니다!몇 초 후
$interval
(또는 파일 전송에 해당 시간이 소요됨) 두 번째 버스트가 발생하면 실행 중인 업데이트 후 프로세스가 종료될 가능성이 높습니다. 그러한 프로세스가 멱등성이거나 트랜잭션이라면 괜찮습니다... 그러니 주의하세요.
답변3
주인. 가능한 해결책은 다음과 같습니다.
inotifywait -m "$dir" -e moved_to --timefmt='%s' --format '%T' | stdbuf -oL uniq | ...
편집하다: IMHO 두 번째 답변이 더 좋기 때문에 이 질문에 대한 다른 답변을 참조하세요.
move_to
단일 파일 전송의 마지막 단계인 각 실행 시 epoch 이후 시간을 인쇄하여 작동합니다 .
업로드가 1초 이상 지속되더라도 업로드 후 프로세스가 여러 번 실행될 수 있지만 이 방법은 제대로 작동합니다.
--timefmt
플래그를 다른 값으로 변경하면 다른 세분성을 얻을 수 있습니다.
별로 마음에 들지는 않지만 반쯤 좋은 생각으로 여기에 게시합니다... 그래도 공유하고 싶었습니다.
답변4
현재 시간을 확인하고 이전 이벤트와 동일한(또는 더 일반적으로 정의할 수 있는 방식으로 유사한) 이벤트를 건너뛰는 루프를 만들 수 있습니다. bash, ksh 또는 zsh에서 다음의 간단한 루프는 10초 내에 반복되는 이벤트를 건너뜁니다.
inotifywait -m … | {
previous_SECONDS=0
previous_event=
while IFS= read -r event; do
if [[ "$event" = "$previous_event" && $SECONDS <= $previous_SECONDS + 10 ]]; then
continue
fi
previous_SECONDS=$SECONDS previous_event=$event
"$post_upload" "$event"
done
}
쉘은 고성능 텍스트 처리에 좋지 않기 때문에 다른 도구를 사용하는 것이 좋습니다. 역사적인 이유로 시간(에포크 이후 초)을 노출하는 매우 이상한 방법이 있는 awk를 사용할 수 있습니다. 호출은 srand()
마지막 호출을 반환합니다 srand()
.
inotifywait -m … | awk '
{srand(); current_time = srand()}
$0 == previous_event && current_time <= previous_time + 10 {
system(ENVIRON["post_upload"])
}
{previous_event = $0; previous_time = current_time}
'
이식성이 꼭 필요한 것이 아니라면 이식성을 포기하고 Perl, Python 또는 Ruby와 같은 더 높은 수준의 스크립팅 언어를 사용하겠습니다. 이러한 언어에는 모두 inotify 인터페이스가 있으므로 호출 inotifywait
하고 텍스트 구문 분석을 수행할 필요가 없습니다 .