Shell betiklerinde doğru kilitleme mi?


66

Bazen bir kabuk betiğinin yalnızca bir örneğinin aynı anda çalıştığından emin olmanız gerekir.

Örneğin, tek başına kilitleme sağlamayan crond üzerinden yürütülen bir cron işi (örneğin, varsayılan Solaris crond).

Kilitlemeyi gerçekleştirmek için kullanılan yaygın bir örnek şudur:

#!/bin/sh
LOCK=/var/tmp/mylock
if [ -f $LOCK ]; then            # 'test' -> race begin
  echo Job is already running\!
  exit 6
fi
touch $LOCK                      # 'set'  -> race end
# do some work
rm $LOCK

Tabii ki, böyle bir kodun bir yarış durumu var. İki örneğin yürütülmesinin, satır 3'ten sonra $LOCKdosyaya dokunmadan önce ilerleyebileceği bir zaman penceresi vardır .

Bir cron işi için bu genellikle bir sorun değildir, çünkü iki çağrı arasında birkaç dakikalık bir zamana sahipsiniz.

Ancak işler ters gidebilir - örneğin, kilit dosyası NFS sunucusundayken - kilitlenir. Bu durumda birkaç cron işi 3. satırda engelleyebilir ve sıraya girebilir. NFS sunucusu tekrar etkinse , paralel çalışan işlerin gürleyen bir süresine sahip olursunuz .

İnternette arama yaparak, bu problem için iyi bir çözüm gibi görünen lockrun aracını buldum . Bununla beraber, böyle kilitlenmesi gereken bir komut dosyası çalıştırın:

$ lockrun --lockfile=/var/tmp/mylock myscript.sh

Bunu bir ambalajın içine koyabilir veya crontab'ınızdan kullanabilirsiniz.

lockf()Varsa (POSIX) kullanır ve flock()(BSD) 'ye geri döner . Ve lockf()NFS üzerinden destek göreceli olarak yaygın olmalıdır.

Alternatifleri var mı lockrun?

Peki ya diğer cron daemons? Akıllıca bir şekilde kilitlenmeyi destekleyen yaygın crondlar var mı? Vixie Crond'un man sayfasına hızlı bir bakış (Debian / Ubuntu sistemlerinde varsayılan) kilitleme ile ilgili hiçbir şey gösterilmiyor.

O gibi bir araç eklemek iyi bir fikir olacağını lockruniçine coreutils ?

Benim düşünceme göre timeout, nicearkadaşlara ve benzeri bir temayı uygulamaktadır .


4
Teğetsel olarak ve başlangıç ​​kalıbınızı İyi Yeter (tm) olarak değerlendirebilecek başkalarının yararına, bu kabuk kodunun, kilitlendiği zaman kilidini çıkarmak için TERM'i sıkıştıracağı kill; ve sadece bir dokunuşundan ziyade, bir kişinin kendi yardımını kilit dosyaya koymak iyi bir uygulama gibi görünüyor.
Ulrich Schwarz,


@Shawn, gerçekten değil, Crond ve NFS'den bahsetmiyor.
maxschlepzig


1
@ Nüfus çok yavaş, PID'yi bir NFS kilit dosyasında depolamak çok az değer katıyor. Ana bilgisayar adını eklemek bile canlı bir işlemi kontrol etmekte hala yardımcı olmuyor
roaima 14:15

Yanıtlar:


45

Aşağıda, yukarıda tanımladığınız yarış koşulunu engelleyebilecek, iki işçinin her ikisinin de 3 satırını geçebileceği kabuk komut dosyasında kilitlemenin başka bir yolu var noclobber. Kullanmayın set noclobberçünkü csh / tcsh ile kod yazmamalısınız. ;)

lockfile=/var/tmp/mylock

if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null; then

        trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT

        # do stuff here

        # clean up after yourself, and release your trap
        rm -f "$lockfile"
        trap - INT TERM EXIT
else
        echo "Lock Exists: $lockfile owned by $(cat $lockfile)"
fi

NFS kilitli YMMV (bildiğiniz gibi, NFS sunucularına erişilemediğinde), ancak genel olarak eskisinden çok daha sağlamdır. (10 yıl önce)

Birden fazla sunucudan aynı anda aynı şeyi yapan cron işleriniz varsa, ancak gerçekten çalışabilmesi için yalnızca 1 örneğe ihtiyacınız varsa, bunun gibi bir şey sizin için işe yarayabilir.

Lockrun ile ilgili hiçbir deneyimim yok, ancak komut dosyasının çalışmasından önce önceden belirlenmiş bir kilitleme ortamına sahip olmak yardımcı olabilir. Ya da olmayabilir. Sen sadece betiğin dışındaki lockfile için testi bir paketleyicide ayarlıyorsun ve teorik olarak, iki iş aynı şekilde aynı zamanda, 'içinde de olduğu gibi lockrun tarafından çağrıldıysa, aynı yarış koşuluna varamazsınız. senaryo çözümü?

Dosya kilitleme, sistem davranışını zaten onurlandırmaktadır ve kilitleme dosyasının varlığını kontrol etmeyen tüm komut dosyaları, yapacakları her şeyi yapacaktır. Sadece lockfile testini ve uygun davranışı uygulayarak,% 100 olmasa da potansiyel problemlerin% 99'unu çözeceksiniz.

Lockfile yarış koşullarına çok fazla rastlarsanız, işlerinizi doğru zamanlamamak veya belki de işlerin tamamlanması iş kadar önemli değilse, belki işinizin daha iyi olması için daha uygunsa, daha büyük bir sorunun göstergesi olabilir. .


AŞAĞIDAKİ EDİT - 2016-05-06 (KSH88 kullanıyorsanız)


@Clint Pachl'ın yorumuna dayanarak, ksh88 kullanıyorsanız, mkdiryerine kullanın noclobber. Bu, çoğunlukla potansiyel bir yarış koşulunu hafifletir, ancak riski (minik olmasına rağmen) tamamen sınırlamaz. Daha fazla bilgi için Clint’in aşağıda gönderdiği linki okuyun .

lockdir=/var/tmp/mylock
pidfile=/var/tmp/mylock/pid

if ( mkdir ${lockdir} ) 2> /dev/null; then
        echo $$ > $pidfile
        trap 'rm -rf "$lockdir"; exit $?' INT TERM EXIT
        # do stuff here

        # clean up after yourself, and release your trap
        rm -rf "$lockdir"
        trap - INT TERM EXIT
else
        echo "Lock Exists: $lockdir owned by $(cat $pidfile)"
fi

Ek bir avantaj olarak, betiğinizde tmpfilo oluşturmanız gerekiyorsa, betiğin çıkmasından sonra lockdirtemizleneceklerini bilerek onlar için dizini kullanabilirsiniz .

Daha modern bash için, üstteki noclobber metodu uygun olmalıdır.


1
Hayır, lockrun ile bir probleminiz olmaz - bir NFS sunucusu kilitlendiğinde, tüm lockrun çağrıları lockf()sistem çağrısında (en azından) askıda kalır - yedeklendiğinde tüm işlemler devam eder, ancak yalnızca bir işlem kilidi kazanır. Yarış koşulu yok. Cronjobs ile bu tür problemlerle pek karşılaşmam - bunun tersi de böyle - ama sana isabet ettiğinde çok fazla acı yaratma potansiyeline sahip bir problem.
maxschlepzig

1
Bu cevabı kabul ettim çünkü metot güvenli ve şimdiye kadarki en şık olanı. Küçük bir değişken öneririm: set -o noclobber && echo "$$" > "$lockfile"kabuk noclobber seçeneğini desteklemediğinde güvenli bir geri dönüş elde etmek için.
maxschlepzig

3
İyi cevap, aynı zamanda kilidi oluşturan sürecin hala var olmasını sağlamak için kilit dosyasındaki değeri '-0' olarak da eklemelisiniz.
Nigel Horne

1
Bu noclobberseçenek yarış koşullarına yatkın olabilir. Bkz mywiki.wooledge.org/BashFAQ/045 düşünce için bazı yiyecek için.
Clint Pachl

2
Not: ksh88'de noclobber(veya -C) kullanılması ksh88 işlevinin kullanılmadığı O_EXCLiçin çalışmaz noclobber. Eğer daha yeni bir kabuk ile çalıştırıyorsanız Tamam olabilir ...
jrw32982

14

Sabit link kullanmayı tercih ederim.

lockfile=/var/lock/mylock
tmpfile=${lockfile}.$$
echo $$ > $tmpfile
if ln $tmpfile $lockfile 2>&-; then
    echo locked
else
    echo locked by $(<$lockfile)
    rm $tmpfile
    exit
fi
trap "rm ${tmpfile} ${lockfile}" 0 1 2 3 15
# do what you need to

Sabit bağlantılar NFS üzerinde atomiktir ve çoğunlukla mkdir . Kullanmak mkdir(2)ya link(2)da pratikte aynı düzeydedir; Ben sadece sabit linkleri kullanmayı tercih ediyorum çünkü NFS uygulamalarında atomik linkten çok atom linklerine izin verildi mkdir. Modern NFS sürümleri ile ikisini de endişelenmenize gerek kalmaz.


12

Bunun mkdiratomik olduğunu anlıyorum , belki:

lockdir=/var/tmp/myapp
if mkdir $lockdir; then
  # this is a new instance, store the pid
  echo $$ > $lockdir/PID
else
  echo Job is already running, pid $(<$lockdir/PID) >&2
  exit 6
fi

# then set traps to cleanup upon script termination 
# ref http://www.shelldorado.com/goodcoding/tempfiles.html
trap 'rm -r "$lockdir" >/dev/null 2>&1' 0
trap "exit 2" 1 2 3 13 15

Tamam, ancak mkdir()NFS (> = 3) üstü atomik olarak standartlaştırılmış olup olmadığı hakkında bilgi bulamadım .
maxschlepzig

2
@ maxschlepzig RFC 1813 açıkça mkdiratomik olduğu söylenmez rename. Uygulamada, bazı uygulamaların olmadığı bilinmektedir . İlgili: GNU kemerin yazar tarafından bir katkı içeren ilginç bir iplik .
Gilles

8

lockfileGenellikle procmailpaketle birlikte gelenleri kullanmak kolay bir yöntemdir .

LOCKFILE="/tmp/mylockfile.lock"
# try once to get the lock else exit
lockfile -r 0 "$LOCKFILE" || exit 0

# here the actual job

rm -f "$LOCKFILE"

5

semGNU parallelaraçlarının bir parçası olarak gelen, aradığınız şey olabilir:

sem [--fg] [--id <id>] [--semaphoretimeout <secs>] [-j <num>] [--wait] command

De olduğu gibi:

sem --id my_semaphore --fg "echo 1 ; date ; sleep 3" &
sem --id my_semaphore --fg "echo 2 ; date ; sleep 3" &
sem --id my_semaphore --fg "echo 3 ; date ; sleep 3" &

çıktısı:

1
Thu 10 Nov 00:26:21 UTC 2016
2
Thu 10 Nov 00:26:24 UTC 2016
3
Thu 10 Nov 00:26:28 UTC 2016

Siparişin garanti edilmediğini unutmayın. Ayrıca çıkış tamamlanıncaya kadar görüntülenmez (tahriş edici!). Ancak yine de, kilit dosyaları, yeniden deneme ve temizleme endişesi olmadan eşzamanlı yürütmeye karşı korumayı bildiğim en özlü yol bu.


Sapın sunduğu kilitleme semyürütme ortasında düşürülüyor mu?
roaima,

2

Kullandığım dtach.

$ dtach -n /tmp/socket long_running_task ; echo $?
0
$ dtach -n /tmp/socket long_running_task ; echo $?
dtach: /tmp/socket: Address already in use
1

1

Burada ve burada açıklandığı gibi bash betiğimdeki kilitleri yönetmek için "flock" komut satırı aracını kullanıyorum . Bu basit metodu, sürü komutundan bazı komutları alt kabuklarda çalıştırmak için kullandım ...

   (
     flock -n 9
     # ... commands executed under lock ...
   ) 9>/var/lock/mylockfile

Bu örnekte, kilit dosyasını alamıyorsa 1 çıkış koduyla başarısız olur. Fakat sürü, ayrıca bir alt kabukta çalıştırılması gereken komutları gerektirmeyen şekillerde de kullanılabilir :-)


3
flock()Sistem çağrısı NFS üzerinden çalışmıyor .
maxschlepzig

1
BSD'nin "lockf" adlı benzer bir aracı vardır.
dubiousjim

2
@dubiousjim, BSD lockf da çağırır flock()ve bu nedenle NFS üzerinden sorunludur. Bu arada, btw, Linux'taki flock () artık fcntl()dosya bir NFS dağı üzerine yerleştirildiğinde geriye düşüyor , bu nedenle Linux-sadece NFS ortamında flock()NFS üzerinde çalışıyor.
maxschlepzig,

1

Dosya kullanmayın.

Komut dosyanız böyle yürütülürse, örneğin:

bash my_script

Aşağıdakileri kullanarak çalıştığını tespit edebilirsiniz:

running_proc=$(ps -C bash -o pid=,cmd= | grep my_script);
if [[ "$running_proc" != "$$ bash my_script" ]]; do 
  echo Already locked
  exit 6
fi

Hm, ps kontrol kodu içeriden my_scriptmi çalışıyor ? Başka bir örnek çalışıyorsa - running_prociki eşleşen satır içermiyor mu? Bu fikri sevdim, ama elbette - başka bir kullanıcı aynı isimdeki bir betiği çalıştırdığında yanlış sonuçlar alırsınız ...
maxschlepzig 5:11

3
Aynı zamanda bir yarış durumu içerir: 2 örneklerini paralel olarak ilk satırını çalıştırmak hiçbiri tek yuvarlak karşılıklı bir tür olacağını 'kilit' ve statü 6. Bu her iki çıkış alır açlık . BTW, örneğin $!yerine neden kullandığınızdan emin değilim $$.
maxschlepzig

@ maxschlepzig gerçekten yanlış $ için üzgünüm! $$
frogstarr78 17

@ maxschlepzig, betiği çalıştıran birden fazla kullanıcıyı işlemek için euser = -o argümanına ekledi.
frogstarr78

@maxschlepzig birden fazla satırı önlemek için argümanları grep olarak değiştirebilir veya ek "filtreler" (örn. grep -v $$) kullanabilirsiniz. Temel olarak soruna farklı bir yaklaşım sunmaya çalışıyordum.
frogstarr78

1

Gerçek kullanım için, en çok oylanan cevabı kullanmalısınız .

Bununla birlikte, psinsanların kullandıklarını görmeye devam ettiğim için kullanmaya başladığım çeşitli kırık ve yarı uygulanabilir yaklaşımları ve sahip oldukları birçok uyarıyı tartışmak istiyorum .

Bu cevap gerçekten "Neden kullanmıyor psve grepkabuktaki kilitlemeyi kullanmıyorsun ?"

Kırık yaklaşım # 1

İlk olarak, bir başka cevapta verilen ve çalışmadığı (ve asla çalışamadığı) ve açıkça hiç test edilmediği gerçeğine rağmen birkaç öneme sahip olan bir yaklaşım :

running_proc=$(ps -C bash -o pid=,cmd= | grep my_script);
if [[ "$running_proc" != "$$ bash my_script" ]]; do 
  echo Already locked
  exit 6
fi

Sözdizimi hatalarını ve bozuk psargümanları düzeltelim ve alalım :

running_proc=$(ps -C bash -o pid,cmd | grep "$0");
echo "$running_proc"
if [[ "$running_proc" != "$$ bash $0" ]]; then
  echo Already locked
  exit 6
fi

Bu komut dosyası olacak hep olursa olsun çalıştırmak nasıl, 6, her seferinde çıkın.

Eğer onu çalıştırırsanız ./myscript, o zaman psçıktı sadece 12345 -bashgerekli dizge ile eşleşmeyecek 12345 bash ./myscript, böylece başarısız olacaktır.

Eğer onu çalıştırırsan bash myscript, işler daha da ilginçleşir. Bash işlemi çatal boru hattını çalıştırmak için ve çocuk kabuk çalıştırır psve grep. Hem orijinal kabuk hem de alt kabuk psçıktıda görünecek , şöyle:

25793 bash myscript
25795 bash myscript

Beklenen çıktı $$ bash $0bu değil, bu yüzden komut dosyanızdan çıkılacak.

Kırık yaklaşım # 2

Şimdi # 1 numaralı yaklaşımı yazan kullanıcıya bütün adalet içinde, bunu ilk denediğimde kendime benzer bir şey yaptım:

if otherpids="$(pgrep -f "$0" | grep -vFx "$$")" ; then
  echo >&2 "There are other copies of the script running; exiting."
  ps >&2 -fq "${otherpids//$'\n'/ }" # -q takes about a tenth the time as -p
  exit 1
fi

Bu neredeyse işe yarıyor. Ancak boruyu çalıştırmak için çatallanma gerçeği bunu atar. Yani bu da daima çıkacak.

Güvenilmez yaklaşım # 3

pids_this_script="$(pgrep -f "$0")"
if not_this_process="$(echo "$pids_this_script" | grep -vFx "$$")"; then
  echo >&2 "There are other copies of this script running; exiting."
  ps -fq "${not_this_process//$'\n'/ }"
  exit 1
fi

Bu sürüm, ilk önce # 2'de mevcut komut dosyasını kendi komut satırı argümanlarında bulunan tüm PID'leri almak ve ardından mevcut komut dosyasının PID'sini atlamak için ayrı ayrı filtrelemek suretiyle boru hattı oluşturma sorununu önler .

Bu işe yarayabilir ... başka hiçbir işlem ile eşleşen bir komut satırı bulunmazsa $0ve komut dosyasının her zaman aynı şekilde çağrılması sağlanır (örneğin, göreceli bir yolla ve sonra mutlak bir yolla çağrılırsa, ikinci örnek önceki ile aynı olmaz) ).

Güvenilmez yaklaşım # 4

Peki ya tam komut satırını kontrol etmeyi atlarsak, bu gerçekten çalışan bir betiği göstermeyebilir ve lsofbunun yerine bu betiği açık olan tüm işlemleri bulmak için kontrol edebilirsek ne olur ?

Evet, bu yaklaşım aslında çok da kötü değil:

if otherpids="$(lsof -t "$0" | grep -vFx "$$")"; then
  echo >&2 "Error: There are other processes that have this script open - most likely other copies of the script running.  Exiting to avoid conflicts."
  ps >&2 -fq "${otherpids//$'\n'/ }"
  exit 1
fi

Tabii ki, betiğin bir kopyası çalışıyorsa, o zaman yeni örnek çalışmaya başlar ve iki kopya çalışır.

Veya çalışan komut dosyası değiştirilirse (örneğin Vim veya a ile git checkout), komut dosyasının "yeni" sürümü sorun çıkarmayacaktır, çünkü hem Vim hem de yerine git checkoutyeni bir dosya (yeni bir inode) çıkar. eski olan.

Ancak, komut dosyası asla değiştirilmez ve hiçbir zaman kopyalanmazsa, bu sürüm oldukça iyidir. Yarış koşulu yoktur, çünkü komut dosyasına kontrole ulaşılmadan önce açık olması gerekir.

Komut dosyası açık olan başka bir işlem açık olsa da yanlış pozitif olabilir, ancak Vim'de düzenleme için açık olsa bile, vim komut dosyasını açık tutmuyor, bu yüzden yanlış pozitif sonuçlanmayacak.

Ancak unutmayın, eğer senaryo düzenlenmiş veya kopyalanmışsa, yanlış negatifler ( yani aynı anda çalışan birden fazla örnek) alacağınız için bu yaklaşımı kullanmayın - Vim ile düzenlemenin yanlış pozitifler vermemesi önemli değil. sana. Yaklaşım 3. çünkü, ama, bundan söz etmez Vim ile açık senaryoyu varsa (yani başlangıç reddediyor) yanlış pozitif vermek.

Öyleyse ne yapmalı?

Bu soruya en çok oylanan cevap iyi bir yaklaşım getiriyor.

Belki daha iyi bir tane yazabilirsiniz ... ama tüm problemleri anlamadıysanız ve yukarıdaki tüm yaklaşımlarla uyarırsanız, hepsini önleyen bir kilitleme yöntemi yazmanız mümkün değildir.



0

İşte makinedeki herhangi bir iş için yarış koşullarını kolayca idare etmek için bazen bir sunucuya eklediğim bir şey. Tim Kennedy'nin gönderisine benzer, ancak bu yolla, ihtiyacı olan her bash betiğine sadece bir satır ekleyerek yarış yönetimi elde edersiniz.

İçeriği örneğin / opt / racechecker / racechecker dizinine koyun:

ZPROGRAMNAME=$(readlink -f $0)
EZPROGRAMNAME=`echo $ZPROGRAMNAME | sed 's/\//_/g'`
EZMAIL="/usr/bin/mail"
EZCAT="/bin/cat"

if  [ -n "$EZPROGRAMNAME" ] ;then
        EZPIDFILE=/tmp/$EZPROGRAMNAME.pid
        if [ -e "$EZPIDFILE" ] ;then
                EZPID=$($EZCAT $EZPIDFILE)
                echo "" | $EZMAIL -s "$ZPROGRAMNAME already running with pid $EZPID"  alarms@someemail.com >>/dev/null
                exit -1
        fi
        echo $$ >> $EZPIDFILE
        function finish {
          rm  $EZPIDFILE
        }
        trap finish EXIT
fi

İşte nasıl kullanılacağı. Shebang'dan sonraki sırayı not edin:

     #/bin/bash
     . /opt/racechecker/racechecker
     echo "script are running"
     sleep 120

Çalışma şekli ana bashscript dosyasının adını bulması ve "/ tmp" altında bir pidfile oluşturmasıdır. Ayrıca bitiş sinyaline bir dinleyici ekler. Ana komut dosyası uygun şekilde sonlandırıldığında dinleyici, pidfile dosyasını kaldırır.

Bir örnek başlatıldığında bir pidfil dosyası varsa, ikinci if-ifadesinin içindeki kodu içeren if ifadesi çalıştırılır. Bu durumda, bu olduğunda bir alarm postası başlatmaya karar verdim.

Ya komut dosyası çökerse

Bir başka uygulama da kazaları ele almak olacaktır. İdeal olarak, ana komut dosyası herhangi bir nedenden ötürü çökse bile, pid dosyası kaldırılmalıdır, bu yukarıdaki sürümümde yapılmaz. Bu, komut dosyası çökerse, işlevsellik geri yüklemek için pidfile elle kaldırılması gerektiği anlamına gelir.

Sistem çökmesi durumunda

Pidfile / lockfile örneğin / tmp altına depolamak iyi bir fikirdir. Bu sayede betikleriniz kesinlikle sistem çökmesinden sonra çalışmaya devam eder, çünkü pidfiles önyüklemede daima silinir.


Tim Kennedy'nin ansatzının aksine, senaryo DOES bir yarış durumu içeriyor. Bunun nedeni, PIDFILE varlığını ve koşullu oluşumunu kontrol etmenizin atomik bir işlemde yapılmamasıdır.
maxschlepzig

Bunun üzerine +1! Bunu göz önünde bulunduracağım ve senaryomu değiştireceğim.
ziggestardust

-2

Senaryomu kontrol et ...

Sen olabilir SEVİYORUM it ....

[rambabu@Server01 ~]$ sh Prevent_cron-OR-Script_against_parallel_run.sh
Parallel RUN Enabled
Now running
Task completed in Parallel RUN...
[rambabu@Server01 ~]$ cat Prevent_cron-OR-Script_against_parallel_run.sh
#!/bin/bash
#Created by RambabuKella
#Date : 12-12-2013

#LOCK file name
Parallel_RUN="yes"
#Parallel_RUN="no"
PS_GREP=0
LOCK=/var/tmp/mylock_`whoami`_"$0"
#Checking for the process
PS_GREP=`ps -ef |grep "sh $0" |grep -v grep|wc -l`
if [ "$Parallel_RUN" == "no" ] ;then
echo "Parallel RUN Disabled"

 if [ -f $LOCK ] || [ $PS_GREP -gt 2   ] ;then
        echo -e "\nJob is already running OR LOCK file exists. "
        echo -e "\nDetail are : "
        ps -ef |grep  "$0" |grep -v grep
        cat "$LOCK"
  exit 6
 fi
echo -e "LOCK file \" $LOCK \" created on : `date +%F-%H-%M` ." &> $LOCK
# do some work
echo "Now running"
echo "Task completed on with single RUN ..."
#done

rm -v $LOCK 2>/dev/null
exit 0
else

echo "Parallel RUN Enabled"

# do some work
echo "Now running"
echo "Task completed in Parallel RUN..."
#done

exit 0
fi
echo "some thing wrong"
exit 2
[rambabu@Server01 ~]$

-3

'Flocktest' isimli bir komut dosyasında aşağıdaki çözümü öneriyorum

#!/bin/bash
export LOGFILE=`basename $0`.logfile
logit () {
echo "$1" >>$LOGFILE
}
PROGPATH=$0
(
flock -x -n 257
(($?)) && logit "'$PROGPATH' is already running!" && exit 0
logit "'$PROGPATH', proc($$): sleeping 30 seconds"
sleep 30
)257<$PROGPATH
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.