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 inotifywait
tarafı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, -e
seçeneğin inotifywait
etkinlik filtrelemesi yapmanın en iyi yolu olduğudur. Ayrıca, read
komutunuz, 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.
inotifywait
istediğ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 incron
yönetimi kolay olduğu için tercih ederim . Temel olarak bu, kaldıraç sağlayan bir hizmettir inotify
ve 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.
inotify
Mevcut değilse en iyi çözüm . Sadece -type f
dosyaları filtrelemek için eklerdim. Aksi takdirde klasör de iade edilir.
-f filename
seç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 espeak
düşü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/…
watch
Komut 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, watch
yalnızca minimum 0.1 saniyeyi destekler.
Hedef klasörün ( isempty
sadece 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 isempty
klasö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_something
işlev isempty
klasö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_something
ve klasör elbette boş değilse eylemi tetikler :
* * * * * if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi
ls
Senaryo yazarken hiç kullanılmamalısın . Yerine find
veya 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.
entr
Kullanmak entr
bunu 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.entr
hı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.-n
Etkileş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.SIGTERM
yeniden 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.entr
soket 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.