Script untuk memonitor folder untuk file baru?


127

Bagaimana cara mendeteksi file baru di folder dengan skrip ? Saya ingin memproses file segera setelah dibuat di folder. Apakah ini mungkin untuk dilakukan atau saya harus menjadwalkan skrip dengan yang memeriksa file baru setiap menit atau lebih?


1
Apakah Anda akan menghapus file dari folder setelah diproses?
ztank1013

Jawaban:


151

Anda harus mempertimbangkan untuk menggunakan inotifywait, sebagai contoh:

inotifywait -m /path -e create -e moved_to |
    while read path action file; do
        echo "The file '$file' appeared in directory '$path' via '$action'"
        # do something with the file
    done

Di Ubuntu inotifywaitdisediakan oleh inotify-toolspaket. Pada versi 3.13 (saat ini di Ubuntu 12.04) inotifywaitakan menyertakan nama file tanpa opsi -f. Versi yang lebih lama mungkin perlu dipaksakan. Yang penting untuk dicatat adalah bahwa -eopsi untuk inotifywaitadalah cara terbaik untuk melakukan penyaringan acara. Selain itu, readperintah Anda dapat menetapkan output posisi menjadi beberapa variabel yang dapat Anda pilih untuk digunakan atau abaikan. Tidak perlu menggunakan grep / sed / awk untuk preprocess output.


1
Bagus! The inotifywaithanya apa yang saya inginkan.
ihatetoregister

2
Hanya ingin memperbarui ini. Anda tidak perlu awk untuk mencapai ini. Anda dapat memfilter acara dengan '-e create' dan hanya mendapatkan nama file dengan melakukan '-f% f' atau path lengkap menggunakan '-f% w% f'. Jadi baris pertama dari skrip di atas menjadi: inotifywait -m / path -f% w% f -e create |
Lugoues

2
@Lugoues dan sekarang ketika Anda mencoba menggunakan -jika Anda mengerti The '--filename' option no longer exists. The option it enabled in earlier versions of inotifywait is now turned on by default., Anda hanya perlu melakukannya, inotifywait -m /path -e create |saya akan mencoba dan mengedit jawaban ini.
Bruno Bronosky

1
Sekarang ada juga alat portabel yang disebutnya fswatch. Saya tidak menulisnya, tapi ini open source dan saya menggunakannya.

1
@Wender inotfiywait menampilkan 3 informasi di satu baris ketika dipicu. Bash builtin 'read' membaca baris input dan memberikan masing-masing dari tiga bagian informasi ke sebuah variabel. Dengan demikian bagian pertama ditugaskan ke jalur variabel, yang kedua untuk bertindak, dan yang ketiga untuk file. Setelah menetapkan nilai ke variabel-variabel tersebut, mereka kemudian tersedia untuk digunakan nanti (seperti pada baris gema). Informasi lebih lanjut: tldp.org/LDP/Bash-Beginners-Guide/html/sect_08_02.html
Tim


24

Saya baru saja memasak ini, dan tidak melihat masalah besar dengan itu, selain kemungkinan kecil file yang hilang di antara cek.

while true
do
       touch  ./lastwatch
       sleep 10
       find /YOUR/WATCH/PATH -cnewer ./lastwatch -exec SOMECOMMAND {} \;
done

Jika pemrosesan file Anda tidak terlalu lama, Anda tidak boleh melewatkan file baru. Anda juga bisa latar belakang kegiatan ... Ini bukan bukti peluru, tetapi melayani beberapa tujuan tanpa alat eksternal seperti inotify.


Tangkapan yang bagus. Saya memperbaikinya sedikit untuk mendukung spasi dalam nama file.
Michael Sacchi

Benar. Itulah caranya. Tidak begitu yakin mengapa saya menyusuri jalan itu, saya menggunakan -exec secara rutin.
Michael Sacchi

itu tidak realtime. realtime selalu yang terbaik
Farhan

3
Solusi terbaik jika inotifytidak tersedia. Saya akan menambahkan -type funtuk memfilter file saja. Kalau tidak, folder juga akan dikembalikan.
Xiao Peng - ZenUML.com

Yap - -f filenameopsinya bagus. Jadi, satu-satunya pertanyaan yang tersisa adalah bagaimana memulai ini saat reboot. Saya akan menggunakan ini dengan pembangkit listrik tenaga surya saya os.system("ssh me@mysystem ' ( touch /home/me/alarms/low24 ) '")sehingga pembuatan file ini akan menyebabkan komputer master menggunakan espeakdan mengumumkan tegangan rendah. Itu sudah mengirim saya email tetapi karena sistem saya sudah berbicara waktu di bagian atas jam itu semua sisanya. askubuntu.com/questions/977613/…
SDsolar

19

Anda dapat menggunakan watchskrip Anda

watch -n 0.1 ls <your_folder>

Monitor folder Anda dan daftarkan semua yang ada di dalamnya setiap 0,1 detik

Kekurangan

Bukan waktu nyata, jadi jika file dibuat dan dihapus dalam waktu kurang dari 0,1 detik, maka ini tidak akan berfungsi, watchhanya mendukung minimum 0,1 detik.


Itulah tepatnya yang saya coba ingat! Terima kasih banyak!!
Joabe Lucena

9

Saya mengasumsikan folder target (saya akan menyebutnya isemptyhanya untuk kenyamanan) kosong dan Anda sedang menunggu satu atau lebih file dijatuhkan di sana.

Anda dapat menggunakan perintah berikut:

ls -1A isempty | wc -l

hanya untuk memeriksa apakah folder tersebut masih kosong, sebenarnya itu akan mengembalikan 0 jika tidak ada file baru (maka isemptyfolder tersebut masih kosong) atau, di sisi lain, itu akan mengembalikan nilai lebih besar dari 0 (sebenarnya jumlahnya file saat ini dalam folder).

Yang mengatakan konyol jika tes dapat membuat sisa pekerjaan:

if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi

Tentu saja do_somethingfungsi harus memanipulasi file dalam isemptyfolder dan kemudian menghapusnya dari folder itu sendiri setelah diproses.

Menambahkan baris seperti berikut di crontab Anda akan menjalankan pemeriksaan satu menit sekali dan akan memicu do_somethingtindakan jika folder tidak kosong tentu saja:

* * * * *     if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi

Solusi ini berfungsi untuk sistem file jarak jauh yang terpasang. pengembang inotify-tools sedang mengerjakan sekering (atau sedang pada pertengahan 2014).
Rondo

3
Anda seharusnya tidak pernah menggunakannya lsuntuk skrip. Gunakan findatau globbing sederhana sebagai gantinya: mywiki.wooledge.org/ParsingLs
andsens

6

Jika Anda ingin mendeteksi file baru, kemudian memprosesnya dan pada akhirnya menghapus file yang diproses Anda dapat menggunakan systemd.path . Metode ini didasarkan pada inotify. Ada opsi DirectoryNotEmpty, jadi systemd dapat menjalankan skrip Anda selalu ketika mendeteksi file dalam direktori. Anda harus ingat itu akan berfungsi hanya jika Anda dapat menghapus file yang diproses dan script meninggalkan direktori kosong.

Pertama-tama siapkan file mymonitor.service

[Unit]
Description=Start the script

[Service]
Type=oneshot
ExecStart=/path/to/your/script

selanjutnya pergi ke mymonitor.path untuk menentukan path

[Unit]
Description= Triggers the service

[Path]
DirectoryNotEmpty=/path/to/monitor

[Install]
WantedBy=multi-user.target

Jika nama file .path sama dengan nama layanan, tidak perlu menentukan nama layanan dalam file .path.

Itu didasarkan pada Pemantauan Akses File untuk Dummies


4

entr

Menggunakan entradalah cara baru untuk melakukan ini (itu lintas platform). Note entrtidak menggunakan polling yang memberikan keuntungan besar dibanding banyak alternatif.

Menggunakan kqueue(2)atau inotify(7)untuk menghindari pemungutan suara. entrditulis untuk membuat umpan balik yang cepat dan pengujian otomatis alami dan sepenuhnya biasa.

Pada BSD yang digunakannya pledge(2)

Anda dapat menginstalnya dengan

apt-get install entr
dnf install entr

Anda dapat melacak direktori untuk penambahan baru menggunakan

while $(true); do
  # echo ./my_watch_dir | entr -dnr echo "Running trigger..."
  echo ./my_watch_dir | entr -dnr ##MY COMMAND##
done;

Opsi dijelaskan (dari dokumen),

  • -d Lacak direktori file biasa yang disediakan sebagai input dan keluar jika file baru ditambahkan. Opsi ini juga memungkinkan direktori ditentukan secara eksplisit. File dengan nama diawali dengan '.' diabaikan.
  • -nJalankan dalam mode non-interaktif. Dalam mode ini, entr tidak mencoba membaca dari TTY atau mengubah propertinya.
  • -r Muat ulang proses anak yang persisten. Seperti halnya mode operasi standar, utilitas yang berakhir tidak dijalankan lagi hingga sistem file atau acara keyboard diproses. SIGTERMdigunakan untuk mengakhiri utilitas sebelum di-restart. Grup proses dibuat untuk mencegah skrip shell dari menutupi sinyal. entrmenunggu utilitas untuk keluar untuk memastikan bahwa sumber daya seperti soket telah ditutup. Kontrol TTY tidak mentransfer proses anak.

2

Bash tidak bisa melakukan ini dengan mudah. Anda pada dasarnya harus mendapatkan daftar semua file di folder dan secara berkala mendapatkan daftar baru dan membandingkannya untuk melihat apa yang berubah.

Apa yang Anda cari disebut inotify. Itu dibangun ke dalam kernel linux dan pada dasarnya Anda bisa duduk di sana menunggu sesuatu terjadi pada saat titik inotify kembali dan berkata 'hei, ada file baru bernama foobar'

Untuk mencapai apa yang Anda inginkan, Anda harus beralih ke sesuatu seperti perl dan menggunakan Linux :: Inotify2 (python mungkin mendukung inotify juga, tapi saya orang perl).


0

Ini berfungsi di cygwin dan Linux. Beberapa solusi sebelumnya yang menulis file akan menyebabkan hard disk rusak. Skrip ini tidak memiliki masalah:

SIG=1
SIG0=$SIG
while [ $SIG != 0 ] ; do
 while [ $SIG = $SIG0 ] ; do
   SIG=`ls -1 | md5sum | cut -c1-32`
   sleep 10
 done
 SIG0=$SIG
 ls -lrt | tail -n 1
done

0

Di bawah ini adalah versi singkat contoh tentang stackoverflow yang telah saya uji dan dimasukkan ke dalam salah satu proyek saya yang memerlukan pemantauan direktori tertentu.

Var_dir="${1:-/tmp}"
Var_diff_sleep="${2:-120}"
Var_diff_opts="--suppress-common-lines"
Func_parse_diff(){
    _added="$(grep -E '>' <<<"${@}")"
    if [ "${#_added}" != "0" ]; then
        mapfile -t _added_list <<<"${_added//> /}"
        _let _index=0
        until [ "${#_added_list[@]}" = "${_index}" ]; do
            _path_to_check="${Var_dir}/${_added_list[${_index}]}"
            if [ -f "${_path_to_check}" ]; then
                echo "# File: ${_path_to_check}"
            elif [ -d "${_path_to_check}" ]; then
                echo "# Directory: ${_path_to_check}"
            if [ -p "${_path_to_check}" ]; then
                echo "# Pipe: ${_path_to_check}"
            fi
            let _index++
        done
        unset _index
    fi
}
Func_watch_bulk_dir(){
    _current_listing=""
    while [ -d "${Var_dir}" ]; do
        _new_listing="$(ls "${Var_dir}")"
        _diff_listing="$(diff ${Var_dec_diff_opts} <(${Var_echo} "${_current_listing}") <(${Var_echo} "${_new_listing}"))"
        if [ "${_diff_listing}" != "0" ]; then
            Func_parse_diff "${_diff_listing}"
        fi
        _current_listing="${_new_listing}"
        sleep ${Var_diff_sleep}
    done
}

Berikut ini tautan ke skrip yang menggunakan versi modifikasi di atas untuk secara otomatis mendekripsi file atau direktori yang ditemukan di sshfs mount point-nya; proyek yang disebutkan sebelumnya.

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.