Script Bash mendeteksi perubahan dalam file dari direktori


10

Saya mencoba membuat skrip yang mendeteksi jika ada file dalam direktori yang diubah dalam interval 2 detik. Sejauh ini yang saya miliki adalah:

#!/bin/bash
for FILE in "${PWD}/*"
do
    SUM1="$(md5sum $FILE)"
    sleep 2
    SUM2="$(md5sum $FILE)"
    if [ "$SUM1" = "$SUM2" ];
    then
        echo "Identical"
    else
        echo "Different"
    fi
done

Ini menghasilkan hanya satu kali nilai "Identik", saya ingin memeriksa setiap file dan output "Identik" atau "Berbeda" untuk setiap file.

Sunting : Bisakah ini dilakukan tanpa menginstal inotify-toolspaket?

Jawaban:


11

Seperti yang telah dijelaskan orang lain, menggunakan inotifyadalah solusi yang lebih baik. Saya hanya akan menjelaskan mengapa skrip Anda gagal. Pertama-tama, apa pun bahasa pemrograman Anda, kapan pun Anda mencoba men-debug sesuatu, aturan pertama adalah "cetak semua variabel":

$ ls
file1  file2  file3
$ echo $PWD    
/home/terdon/foo
$ for FILE in "${PWD}/*"; do echo "$FILE"; done
/home/terdon/foo/*

Jadi, seperti yang Anda lihat di atas, $FILEsebenarnya diperluas ke $PWD/*. Oleh karena itu, loop hanya dijalankan sekali pada string /home/terdon/foo/* dan bukan pada masing-masing file dalam direktori secara individual. Kemudian, md5sumperintahnya menjadi:

md5sum /home/terdon/foo/*

Dengan kata lain, ini berjalan md5sumpada semua file di direktori target sekaligus dan tidak pada masing-masing file.

Masalahnya adalah Anda mengutip ekspansi glob Anda dan itu menghentikan ekspansi:

$ echo "*"
*
$ echo *
file1 file2 file3

Sementara variabel hampir selalu dikutip , gumpalan tidak seharusnya karena itu membuat mereka menjadi string, bukan gumpalan.

Yang ingin Anda lakukan adalah:

for FILE in "${PWD}"/*; do ...

Namun, tidak ada alasan untuk digunakan di $PWDsini, itu tidak menambahkan sesuatu yang bermanfaat. Baris di atas setara dengan:

for FILE in *; do

Juga, hindari menggunakan huruf MODAL untuk variabel shell. Itu digunakan untuk variabel lingkungan yang ditetapkan sistem dan lebih baik menjaga variabel Anda sendiri dalam huruf kecil.

Dengan mengingat semua ini, inilah versi skrip Anda yang berfungsi dan lebih baik:

#!/bin/bash
for file in *
do
    sum1="$(md5sum "$file")"
    sleep 2
    sum2="$(md5sum "$file")"
    if [ "$sum1" = "$sum2" ];
    then
        echo "Identical"
    else
        echo "Different"
    fi
done

Sementara for FILE in "${PWD}"/*; dobekerja pada set yang sama karena for FILE in *; dotidak persis sama karena yang terakhir tidak termasuk nama path.
Lambert

1
@Lambert benar, tetapi tidak ada bedanya di sini karena, menurut definisi, skrip akan dijalankan dari $ PWD
terdon

Ini akan menjadi ide yang baik untuk digunakan md5sum -- "$file"daripada md5sum "$file"menangani kasus di mana file dimulai dengan a -. Tentu saja Anda juga harus membuat implementasi md5sum mendukung --akhir opsi pembatas.
Harold Fischer

9

Anda dapat menggunakan alat-alat inotify secara pasti dari baris perintah, misalnya seperti ini:

inotifywait -r  -m /dir/to/monitor/

Dari manusia tidak menunggu

-m, --monitor

Alih-alih keluar setelah menerima satu peristiwa tunggal, jalankan tanpa batas. Perilaku default adalah untuk keluar setelah peristiwa pertama terjadi.

Dan berikut ini adalah skrip yang memonitor secara terus-menerus, disalin dari file manual inotifywait:

#!/bin/sh
while inotifywait -e modify /var/log/messages; do
  if tail -n1 /var/log/messages | grep apache; then
    kdialog --msgbox "Blah blah Apache"
  fi
done

5

Anda dapat menggunakan inotify-toolspaket untuk memantau semua perubahan dalam folder secara real time. Misalnya, ini berisi inotifywaitalat, yang bisa Anda gunakan seperti:

> inotifywait /tmp
Setting up watches.
Watches established.
/tmp/ MODIFY test

Anda dapat menggunakan tanda untuk memfilter peristiwa tertentu saja atau file tertentu. The inotifywatchalat Mengumpulkan filesystem statistik penggunaan dan output jumlah masing-masing inotifyacara.

Anda dapat menemukan lebih banyak contoh di sini misalnya.

Jika Anda ingin memantau dengan alat lain, Anda dapat menggunakan finddengan -mminparameter (menit yang dimodifikasi). Karena 2 detik seperti 0,033 menit, Anda dapat menggunakan:

find . -type f -mmin 0.033

1

Jika Anda ingin memantau pada interval dua detik, Anda dapat mengelilingi cek Anda dengan:

while true
do
    <your steps>
    sleep 2
done

Meskipun ini akan secara berurutan menguji file dan akan menunggu 2 detik untuk setiap file yang ditemukan saya sarankan untuk mengubah cek Anda menjadi fungsi:

function _check_file()
{
    SUM1=$(md5sum "$@")
    sleep 2
    SUM2=$(md5sum "$@")
    if [ "$SUM1" == "$SUM2" ];
    then
        echo "$@: Identical"
    else
        echo "$@: Different"
    fi
}

Yang bisa digunakan dalam whileloop:

while true
do
    for FILE in "${PWD}/"*
    do
        if [ -f "$FILE" ]
        then
            _check_file "$FILE" &
        fi
    done
    sleep 2
done

Harap perhatikan tanda dan &untuk melakukan pemeriksaan di latar belakang untuk melakukan pemeriksaan file secara paralel. Perhatikan bahwa ini dapat berdampak pada kinerja tergantung pada jumlah file yang ditemukan di direktori.

Juga perhatikan bahwa saya mengubah echobaris untuk memasukkan nama file ( "$@") untuk memvisualisasikan file mana yang ditemukan identik / berbeda.


0
#!/bin/bash
# pass one or more folders as arguments
while true; do
  for f in "$@"; do
    date
    echo "Checking $f and subfolders"
    find=$(find "$f" -type f)
    while read -r f2; do
      # strip non-alphanumeric from filename for a variable var name
      v=${f2//[^[:alpha:]]/}
      r=$(md5sum "$f2")
      if [ "$r" = "${!v}" ]; then
        echo "Identical $f2"
      else
        echo "Different $f2"
      fi
      eval "${v}=\$r"
    done <<< "$find"
  done
  sleep 2
done
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.