Yeni dosyalar için klasörü izlemek için komut dosyası?


127

Bir betiği olan bir klasördeki yeni dosyalar nasıl tespit edilir ? Dosyaları klasörde oluşturuldukları anda işleme koymak istiyorum. Bunu yapmak mümkün mü yoksa her dakika yeni dosyaları kontrol eden bir betik programlamalı mıyım?


1
İşlendikten sonra dosyaları klasörden kaldıracak mısınız?
ztank1013

Yanıtlar:


151

inotifywaitÖrnek olarak kullanmayı düşünmelisiniz :

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

Ubuntu'da paket inotifywaittarafından sağlanmaktadır inotify-tools. 3.13 sürümünden itibaren (Ubuntu 12.04'te geçerli olan) inotifywait, -f seçeneği olmayan dosya adını içerecektir. Eski sürümlerin zorlanması gerekebilir. Unutulmaması gereken şey, -eseçeneğin inotifywaitetkinlik filtrelemesi yapmanın en iyi yolu olduğudur. Ayrıca, readkomutunuz, pozisyon çıktısını kullanmayı veya yoksaymayı seçebileceğiniz birden fazla değişkene atayabilir. Çıktıyı önceden hazırlamak için grep / sed / awk kullanmanıza gerek yoktur.


1
Harika! Tam inotifywaitistediğim buydu.
imhatetoregister

2
Sadece bunu güncellemek istiyorum. Bunu başarmak için awk gerekmez. olayları '-e create' ile filtreleyebilir ve '-f% f' veya '-f% w% f' komutunu kullanarak tam yolunu yaparak yalnızca dosya adını alabilirsiniz. Böylece yukarıdaki betiğin ilk satırı şöyle olur: inotifywait -m / path -f% w% f -e create |
Lugoues

2
@Lugoues ve şimdi kullanmaya çalıştığınızda -f alırsanız The '--filename' option no longer exists. The option it enabled in earlier versions of inotifywait is now turned on by default.Yani, sadece yapmanız gereken inotifywait -m /path -e create |bu cevabı düzenlemeye çalışacağım.
Bruno Bronosky

1
Şimdi bunun için bir de taşınabilir araç var fswatch. Yazmadım ama açık kaynak ve kullanıyorum.

1
@Wender inotfiywait, tetiklendiğinde, tek bir hatta 3 parça bilgi verir. 'Read' bash yerleşimi giriş satırını okur ve üç bilgiden her birini bir değişkene atar. Böylece, birinci parça değişken yola, ikincisi harekete, diğeri dosyaya atanır. Bu değişkenlere değer atadıktan sonra, daha sonra kullanılmak üzere hazır olurlar (eko satırındaki gibi). Daha fazla bilgi: tldp.org/LDP/Bash-Beginners-Guide/html/sect_08_02.html
Tim


24

Bunu yeni öğrendim ve çekler arasında dosya eksik olma ihtimalinden başka büyük bir sorun görmedim.

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

Dosya işlemeniz çok uzun sürmezse, yeni bir dosyayı kaçırmamalısınız. Ayrıca etkinlikleri de arka plana dahil edebilirsiniz ... Kurşun geçirmez değildir, ancak inotify gibi harici araçlar olmadan bazı amaçlara hizmet eder.


İyi yakalama. Dosya adlarındaki boşlukları desteklemek için onu biraz geliştirdim.
Michael Sacchi

Kesinlikle. Gidecek yol bu. Bu yoldan neden indiğimden tam olarak emin değilim, -exec'i rutin olarak kullanıyorum.
Michael Sacchi

gerçek zamanlı değil. gerçek zamanlı her zaman en iyisidir
Farhan

3
inotifyMevcut değilse en iyi çözüm . Sadece -type fdosyaları filtrelemek için eklerdim. Aksi takdirde klasör de iade edilir.
Xiao Peng - ZenUML.com

Evet - -f filenameseçenek harika. Öyleyse geriye kalan tek soru, bunun yeniden başlatmaya başlamasının nasıl sağlanacağı. Bunu güneş santralimle birlikte kullanacağım, bu os.system("ssh me@mysystem ' ( touch /home/me/alarms/low24 ) '")yüzden bu dosyanın oluşturulması ana bilgisayarın espeakdüşük gerilimi kullanmasına ve duyurmasına neden olacaktır . Bana zaten bir e-posta gönderir, ancak sistemim zaten saatin başında zaman konuşur çünkü geri kalan her şey var. askubuntu.com/questions/977613/…
SDsolar

17

watchKomut dosyanızda kullanabilirsiniz

watch -n 0.1 ls <your_folder>

Klasörünüzü izler ve her 0.1 saniyede bir size her şeyi listeler

sakınca

Gerçek zamanlı değildir, bu nedenle bir dosya 0.1 saniyeden kısa bir sürede oluşturulmuş ve silinmişse, bu işe yaramazsa, watchyalnızca minimum 0.1 saniyeyi destekler.


Tam olarak hatırlamaya çalıştığım şey buydu! Çok teşekkürler!!
Joabe Lucena

9

Hedef klasörün ( isemptysadece kolaylık olması için arayacağım ) boş olduğunu ve oraya bir veya daha fazla dosyanın bırakılmasını beklediğimi farz ediyorum .

Aşağıdaki komutu kullanabilirsiniz:

ls -1A isempty | wc -l

sadece klasörün hala boş olup olmadığını kontrol etmek için, aslında yeni bir dosya yoksa 0 döndürür (bu nedenle isemptyklasör hala boş) veya diğer taraftan 0'dan büyük bir değer döndürür (aslında sayı şu anda klasördeki dosyaların listesi).

Aptalca eğer / sonra test işin geri kalanını yapabilir, dedi:

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

Elbette, do_somethingişlev isemptyklasör içindeki dosyaları işlemek ve işlemden sonra bunları klasörden kaldırmak zorunda kalacaktır .

Crontab'ınıza aşağıdaki gibi bir satır eklemek, kontrolü dakikada bir kez çalıştırır do_somethingve klasör elbette boş değilse eylemi tetikler :

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

Bu çözüm bağlı uzak dosya sistemlerinde çalışır. inotify-tools developer (s) sigorta üzerinde çalışıyor (veya 2014 ortasında idi).
Rondo

3
lsSenaryo yazarken hiç kullanılmamalısın . Yerine findveya basit globbing kullanın: mywiki.wooledge.org/ParsingLs
andsens 28:06

6

Yeni dosyaları algılamak istiyorsanız, onları işleyin ve sonunda devam eden dosyaları silmek systemd.path kullanabilirsiniz . Bu yöntem inotify'ı temel alır. Bir seçenek DirectoryNotEmpty vardır, böylece sistemd, dizinde herhangi bir dosyayı algıladığında komut dosyanızı her zaman çalıştırabilir. Sadece devam eden dosyaları silebilir ve script dizini boş bırakırsa işe yarayacağını unutmamalısınız.

Önce mymonitor.service dosyasını hazırlayın

[Unit]
Description=Start the script

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

daha sonra yolu tanımlamak için mymonitor.path öğesine gidin.

[Unit]
Description= Triggers the service

[Path]
DirectoryNotEmpty=/path/to/monitor

[Install]
WantedBy=multi-user.target

.Path dosyasının adı hizmetin adıyla aynıysa, hizmet adını .path dosyasında belirtmenize gerek yoktur.

Aptallar için Dosya Erişimini İzleme konusuna dayanır


4

entr

Kullanmak entrbunu yapmanın yeni yoludur (çapraz platformdur). Not entr, birçok alternatif üzerinde büyük bir avantaj sağlayan yoklama kullanmaz.

Kullanım kqueue(2)veya inotify(7)yoklamayı önlemek için. entrhızlı geri bildirim ve otomatik testi doğal ve tamamen sıradan hale getirmek için yazılmıştır.

BSD'de kullanır pledge(2)

İle yükleyebilirsiniz

apt-get install entr
dnf install entr

Yeni eklemeler için bir dizini kullanarak

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

Açıklanan seçenekler (dokümanlardan),

  • -d Girdi olarak sağlanan normal dosyaların dizinlerini izleyin ve yeni bir dosya eklenirse çıkın. Bu seçenek ayrıca dizinlerin açıkça belirtilmesini sağlar. '.' İle başlayan adları olan dosyalar göz ardı edilir.
  • -nEtkileşimli olmayan modda çalıştırın. Bu modda entr, TTY'den okumaya veya özelliklerini değiştirmeye çalışmaz.
  • -r Kalıcı bir çocuk süreci yeniden yükleyin. Standart çalışma modunda olduğu gibi, sonlandırılan bir yardımcı program bir dosya sistemi veya klavye olayı işlenene kadar bir daha yürütülmez. SIGTERMyeniden başlatılmadan önce yardımcı programı sonlandırmak için kullanılır. Kabuk komut dosyalarının sinyalleri maskelemesini önlemek için bir işlem grubu oluşturulur. entrsoket gibi kaynakların kapatıldığından emin olmak için yardımcı programın çıkmasını bekler. TTY'nin kontrolü çocuk sürecine aktarılmaz.

2

Bash bunu kolayca yapamaz. Temelde klasördeki tüm dosyaların bir listesini almanız ve periyodik olarak yeni bir liste almanız ve nelerin değiştiğini görmek için bunları karşılaştırmanız gerekir.

Aradığın şey inotify. Linux çekirdeği içine yerleştirilmiştir ve temelde orada inotify'ın geri döndüğü ve 'hey, foobar adında yeni bir dosya var' diyen bir şeyin olmasını bekleyerek oturabilirsiniz.

İstediğinizi başarmak için perl gibi bir şeye geçmeniz ve Linux :: Inotify2 kullanmanız gerekir (python muhtemelen inotify'ı da destekler, ancak ben perl bir insanım).


0

Bu cygwin ve Linux'ta çalışır. Dosya yazan önceki çözümlerden bazıları diskin bozulmasına neden olur. Bu yazı yazısının sorunu yok:

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

Aşağıda, belirli dizinlerin izlenmesini gerektiren projelerimden birine test ettiğim ve eklediğim stackoverflow örneğinin kısaltılmış bir versiyonu verilmiştir .

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
}

Burada , sshfs bağlama noktasında bulunan dosyaların veya dizinlerin otomatik olarak şifresini çözmek için yukarıda değiştirilmiş bir sürümünü kullanan bir betiğin bağlantısı ; Yukarıda belirtilen proje.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.