파일 관찰 및 체크섬 비교

파일 관찰 및 체크섬 비교

스크립트를 사용하여 파일을 관찰하고 60초마다 파일의 md5sum을 비교하고 변경된 경우 화면에 경고를 인쇄해 보세요.

무엇을 해야할지 모르겠습니다. 그게 내가 갖고 있는건데, 좀 벗어난 것 같아

#/bin/bash

watch=$@

if [ -z "$watch" ]
    then
        echo "No file specified, aborting"
        exit 
else
    echo "watching : $watch"
fi

while [ 1 ]; do
watch -n 60 -d md5sum $watch
done

나도 이 작업을 수행했는데 작동하는 것 같습니다(일종의). 파일이 변경되었는지 알려 주지만 watch 명령을 사용하지 않습니다. watch를 통해 이를 수행할 수 있는 방법이 있습니까?

#/bin/bash

watch=$@

if [ -z "$watch" ]
   then
       echo "No file specified, aborting"
       exit 
else
    echo "watching : $watch"
fi

checksum1="empty"
while [ 1 ]; do

checksum2=$(md5sum $watch | md5sum | cut -d ' ' -f1)
if [ "$checksum2" != "$checksum1" ];
then
echo "Warning : $watch has been changed"
#mail -s "$watch has been changed" "[email protected]"
echo -e "\a"
fi
checksum1="$checksum2"
sleep 60
done

답변1

당신은 훨씬 더 나은 상황에 있습니다inotify, 이는 파일 모니터링이라는 목적으로 만들어졌습니다.


편집하다: 링크된 질문에 대한 답변을 여기에 정리하겠습니다.

파일이나 디렉터리를 모니터링해야 할 때마다 inotify는 해당 작업에 적합한 도구입니다. 모니터링하려는 이벤트(파일 액세스, 변경, 열기, 닫기, 삭제 등)를 inotifywait에 알릴 수 있습니다( man inotifywait자세한 내용 보기).

첫 번째 방법은 다음과 같은 루프입니다.

while inotifywait -e close_write myfile.py; do ./myfile.py; done

가장 큰 단점은 이벤트를 놓칠 수 있다는 것입니다. 보다 효율적인 버전은 다음과 같습니다.

inotifywait -mq --format '%e' /path/to/file |
while IFS= read -r events; do
  /path/to/script "$events"
done

이 후자 버전을 사용하면 이벤트를 놓치지 않을 것입니다. 파이프는 이벤트가 대기열에 있는지 확인합니다. 루프가 제 시간에 선택하지 않으면 쌓이지만 누락된 항목은 없습니다.


편집하다: 텍스트 파일을 추적하는 경우 강력한 해시를 사용하여 파일을 추적하므로 git도 권장합니다. 다음은 메인 루프에 대한 bash 의사코드입니다 inotify:

git status file     # Tells whether <file> was modified
if file was modified; then
    git commit -- file  # Add <file> to the repository
    keep only the last two versions of <file>
    print the warning message
fi

이것을 베이스로 사용할 수 있습니다. 어쩌면 git출력을 구문 분석해야 할 수도 있습니다 . 나는 당신에게 정확한 방법을 말할 만큼 충분히 사용하지 않았지만 그것이 트릭을 수행할 수 있을 것 같은 직감이 있습니다 ;-).

답변2

나는 이 대답을 싫어하지만 약 15분 동안 이 대답을 가지고 놀아본 후에는 명령으로 그것을 달성할 수 있는 방법이 없다고 생각합니다. watch(다른 사람들은 내가 틀렸다는 것을 증명해주세요.)

문제는 watch자체 루프에서 자체적으로 실행되며 쉘에 데이터 공급을 중단하지 않고 자체 에코만 제공한다는 것입니다.

watchrun이 작동하는 방식 으로 인해 어떤 종류의 ifor whilecheck 문에서든 이를 사용하면 쉘이 결과를 반환하지 않기 때문에 변경 사항을 평가할 기회가 제공되지 않습니다. 루프를 수동으로 종료할 때까지 이를 유지합니다.

두 번째 예에서와 같이 자신만의 루프를 실행하고 md5sum을 확인하는 것이 원하는 작업을 수행하는 가장 좋은 방법입니다.

예를 들어, 질문

echo `watch -d md5sum testfile.txt`

메아리는 결코 사라지지 않습니다. 에코가 터미널에 도달하도록 하는 방법을 찾을 수 있다면,저것스크립트를 실행하는 답입니다.

답변3

파일 매개변수를 제공하고 md5sum을 사용한다는 아이디어를 따르는 이 조잡한 스크립트를 사용해 보세요. md5sum이 변경될 때마다 타임스탬프가 표시된 행을 표시하고 로그 파일을 저장하며 ctrl-c를 누르면 중지됩니다. 콘텐츠 watch_and_notify.sh:

#!/bin/bash

logf="$1.log"

interval=2

first_run=

# temp files, current and last md5s for diff to compare
lm1="$(mktemp /tmp/lm1.$$.XXXX)"
lm2="$(mktemp /tmp/lm2.$$.XXXX)"

if [ -z "$1" ]; then
        echo "No file specified, aborting" >&2
        exit 1
fi

echo "Watching at ${interval}s intervals:   $1"

# loop forever until cancel this script
while true; do

    md5sum "$1" > $lm1

    # otherwise in the first iteration,
    # lm2 does not yet exist, so diff
    # will always unintentionally report
    # a difference when comparing existing
    # file with nonexisting file
    if [ -z "$first_run" ]; then
        cp -a $lm1 $lm2
        first_run=1
    fi

    # test ! to invert usual exit code
    if ! diff $lm2 $lm1; then
        echo -e "$(date +"%F %R")\tChange detected:\t$1" | tee -a "$logf"
    fi

    # rotate
    mv $lm1 $lm2

    sleep $interval

done

# when you ctrl-c it should garbage cleanup
trap "rm $lm1 $lm2; exit 1" SIGINT

다음 이름의 빈 텍스트 파일을 시작합니다.a.txt

$ touch a.txt

다음과 같이 스크립트를 실행하고 다음을 확인하세요.

$ ./watch_and_notify.sh a.txt
Watching at 2s intervals:       a.txt

두 번째 터미널에서는 변경 사항을 테스트합니다.

$ echo addition >> a.txt

첫 번째 터미널에서 스크립트를 실행하면 업데이트가 표시됩니다.

Watching at 2s intervals:       a.txt

1c1
< d41d8cd98f00b204e9800998ecf8427e  a.txt
---
> 9913e6909c108b5c32c69280474b2b2a  a.txt
2015-09-29 15:56        Change detected:        a.txt

두 번째 터미널에서 또 다른 변경 사항을 적용합니다.

$ echo anotherchange >> a.txt

그런 다음 스크립트를 실행하는 첫 번째 터미널에서 출력이 다시 업데이트됩니다.

Watching at 2s intervals:       a.txt
1c1
< d41d8cd98f00b204e9800998ecf8427e  a.txt
---
> 9913e6909c108b5c32c69280474b2b2a  a.txt
2015-09-29 15:56        Change detected:        a.txt
1c1
< 9913e6909c108b5c32c69280474b2b2a  a.txt
---
> 5c1c20a75b9982128f8300a7940f9ce0  a.txt
2015-09-29 16:06        Change detected:        a.txt

당신은 그만 두었습니다 ctrl-c. 명령 프롬프트로 돌아갑니다. 콘텐츠를 나열하고 로그가 있는지 확인합니다.

$ ls -lh
total 12K
-rw-r--r-- 1 meme meme  22 Sep 29 16:06 a.txt
-rw-r--r-- 1 meme meme  80 Sep 29 16:06 a.txt.log
-rwxrwxrwx 1 meme meme 775 Sep 29 15:26 watch_and_notify.sh

로그를 보면 변경 순간을 기록하는 동일한 타임스탬프 항목을 볼 수 있습니다.

$ cat a.txt.log
2015-09-29 15:56        Change detected:        a.txt
2015-09-29 16:06        Change detected:        a.txt

코드 설명

전체적인 흐름의 대부분은 스크립트에 있는 주석을 보면 알 수 있지만 기본적으로 파일에 대해 md5sum 명령을 반복적으로 실행하면서 결과를 저장하고 회전시켜서 프로그램이 diff현재 결과를 이전 반복 결과와 비교하도록 합니다(만일 모두) 그런 다음 보고 작업을 수행합니다. 이 경우 이러한 작업은 타임스탬프와 함께 화면에 출력되고 로그에 추가됩니다. 사용자는 ctrl-c를 사용하여 스크립트를 중지하고 차이가 감지된 타임스탬프 순간의 로그를 남깁니다.

스크립트 내에서

lm1="$(mktemp /tmp/lm1.$$.XXXX)"
lm2="$(mktemp /tmp/lm2.$$.XXXX)"
  • lm1 및 lm2는 비교를 위해 md5sum 출력을 저장하는 데 사용되는 임시 파일이며 스크립트를 실행할 때만 생성됩니다.
  • 당신이 말했듯이 핵심 방법은 문자 그대로 md5sum을 비교하므로 이를 위해 먼저 이를 저장할 임시 장소를 정의합니다.
  • mktemp고유한 임시 파일 이름을 만드는 데 도움이 됩니다.
  • $$현재 프로세스 ID이며 임의성을 추가합니다.
  • XXXXX각 문자를 임의의 영숫자 문자로 mktemp바꾸도록 지시합니다.X

따라서 런타임 시 /tmp에 우리가 정의한 패턴으로 명명된 파일이 하나 이상 포함되어 있는지 확인할 수 있습니다.

$ ls -lh /tmp/lm*
-rw-r--r-- 1 meme meme 40 Sep 29 15:08 /tmp/lm2.8248.xGJTl

다음으로 while 루프가 있습니다.

# loop forever until cancel this script
while true; do

...

done

대부분의 코드는 큰 while <command>; do ... done루프에 끼워져 있습니다. 명령/조건이 true항상 true이므로 이 코드는 중지할 때까지 무기한 실행됩니다 ctrl-c.

각 루프 반복은 먼저 현재 반복의 md5sum 결과를 생성하고 저장합니다.

md5sum "$1" > $lm1
  • $1첫 번째 위치 매개변수를 나타냅니다. 이 경우 실행하면 다음과 같습니다 watch_and_notify.sh a.txt.$1a.txt
  • > $lm1이전에 정의한 임시 파일에 출력 쓰기

처음 실행되면 이전 반복이 없습니다. 그러나 명령은 diff이전 md5sum 결과의 변경 사항을 $lm2 와 비교 해야 하는 방식으로 배열되어 있습니다 $lm1. 이는 첫 번째 실행에서 항상 실수로 차이점을 표시하므로 첫 번째 실행에서는 특별한 조건부 연산이 필요합니다. 첫 번째 실행을 인식할 수 있도록 while루프 전에 정의된 초기 빈 변수를 만듭니다 .

first_run=

그런 다음 루프에서 다음을 테스트합니다.

    if [ -z "$first_run" ]; then
        cp -a $lm1 $lm2
        first_run=1
    fi
  • -z0 값을 테스트합니다. 첫 번째 반복인 경우 $first_run은 항상 비어 있으므로 해당 then섹션을 계속 진행하세요.
  • then섹션에서는 "이전 반복"을 복사하여 "가짜"로 만듭니다. $lm1따라서 나중에 diff첫 번째 반복에서는 두 개의 동일한 파일을 비교하고 차이점이 보고되지 않습니다.
  • first_run=1이렇게 하면 다음 반복에서는 if [ -z "$first_run" ]; then$first_run이상 0 값이 아니므로 이 then부분은 트리거되지 않으므로 이 작업은 첫 번째 반복에서만 수행됩니다.

diff다음으로 이전 반복의 md5sum 결과(변수에서 참조되는 파일에 저장됨) $lm2와 현재 반복의 md5sum 결과(변수에서 참조되는 파일에 저장됨)를 비교하는 실제 조건이 있습니다.$lm1

if ! diff $lm2 $lm1; then
  • diff우리는 명령의 종료 코드에 반응하는 데 의존합니다.
  • diff file1 file2동일한 경우 일반적으로 종료 코드 0이 발생합니다. 런타임에 이를 테스트하면 $ diff a.txt a.txt; echo $?0이 표시됩니다. 서로 다를 때, 예 $ diff a.txt b.txt; echo $?를 들어 b.txt서로 다른 한 결과가 있을 것입니다.1
  • 그러나 0bash는 그 의미가 다음 true1같다고 생각합니다.false
  • 따라서 파일이 동일할 때 다음으로 해석되고 섹션을 트리거하는 종료 코드 0을 제공하기 if diff $lm2 $lm1; then때문에 이 작업을 수행할 수 없습니다.difftruethen
  • 우리는 반대되는 행동을 원하고, 같으면 아무것도 하지 않고, 다르면 무엇인가를 합니다.
  • !출력 반전 도움말

따라서 변경 사항을 테스트할 수 있습니다.

변경이 발생하면 취해지는 조치는 다음과 같습니다.

    echo -e "$(date +"%F %R")\tChange detected:\t$1" | tee -a "$logf"
  • echo-e렌더링을 \t탭으로 사용
  • date +"%F %R"현재 타임스탬프를 지정된 형식으로 렌더링합니다(예: 2015-09-29 15:56).
  • |tee프로그램 으로 파이프 출력
  • tee발생한 변경 사항에 대한 출력 메시지를 보고 출력을 저장할 수 있습니다.
  • -a저장 방법을 추가로 설정하세요. 그렇지 않으면 결과가 있을 때마다 이전 결과를 덮어쓰게 됩니다.

현재 반복 작업이 거의 완료되었습니다. diff비교 및 연산을 완료 한 후 다음 반복을 준비하기 위해 다음을 수행합니다.

    mv $lm1 $lm2
  • mv$lm1에 저장된 현재 반복의 md5sum 결과를 에서 로 이동하거나 이름을 바꿉니다 $lm2.
  • 따라서 diff $lm2 $lm1다음 반복에서는 실제로 이전 반복의 md5sum을 비교합니다.

마지막 루프의 마지막 줄은 sleep 절 sleep $interval입니다.

  • sleep$interval변수로 제공되는 결과 지연(초)
  • $interval파일 시작 부분에 설정된 변수는 다음과 같습니다.2
  • 따라서 각 반복은 2초 동안 지속됩니다.

    완벽한

  • done마지막에 닫는 while ...;do ... done루프가 있습니다.

관련 정보