Bir bash 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 cronlu bir betik programlamalı mıyım?
Bir bash 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 cronlu bir betik programlamalı mıyım?
Yanıtlar:
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.
inotifywaitistediğim buydu.
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.
fswatch. Yazmadım ama açık kaynak ve kullanıyorum.
Ben incronyönetimi kolay olduğu için tercih ederim . Temel olarak bu, kaldıraç sağlayan bir hizmettir inotifyve dosya değişikliği işlemlerine dayanarak işlem yapmak üzere yapılandırmaları ayarlayabilirsiniz.
Ör:
<directory> <file change mask> <command or action> options
/var/www/html IN_CREATE /root/scripts/backup.sh
Burada tam bir örnek görebilirsiniz: http://www.cyberciti.biz/faq/linux-inotify-examples-to-replicate-directories/
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.
inotifyMevcut değilse en iyi çözüm . Sadece -type fdosyaları filtrelemek için eklerdim. Aksi takdirde klasör de iade edilir.
-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/…
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.
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
lsSenaryo yazarken hiç kullanılmamalısın . Yerine findveya basit globbing kullanın: mywiki.wooledge.org/ParsingLs
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.
entrKullanmak 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)veyainotify(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),
-dGirdi 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.-rKalı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.
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).
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
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.