En iyisi, timeout
komutun bunun için olması durumunda kullanılmasıdır:
timeout 86400 cmd
Mevcut (8.23) GNU uygulaması en azından alarm()
çocuk sürecini beklerken ya da eşdeğerini kullanarak çalışır . Geri dönüş ile çıkış SIGALRM
arasında teslim edilmesine karşı koruma sağladığı görülmemektedir (bu alarmı etkin bir şekilde iptal etme ). Bu küçük pencere sırasında , stderr üzerine (örneğin çocuk bir göbek attıysa) bu yarış penceresini daha da büyütecek (örneğin stderr örneğin bir boru ise süresiz olarak) mesajlar yazabilir.waitpid()
timeout
timeout
Şahsen ben bu sınırlama ile yaşayabilirim (ki bu muhtemelen gelecekteki bir versiyonda düzeltilecektir). timeout
ayrıca doğru çıkış durumunu bildirmek, diğer köşe kasalarını (başlangıçta engellenen / yok sayılan SIGALRM gibi) ele almayı, muhtemelen elle yapmayı düşündüğünüzden daha iyi ele almaya da özen gösterir.
Bir yaklaşım olarak, şöyle yazabilirsiniz perl
:
perl -MPOSIX -e '
$p = fork();
die "fork: $!\n" unless defined($p);
if ($p) {
$SIG{ALRM} = sub {
kill "TERM", $p;
exit 124;
};
alarm(86400);
wait;
exit (WIFSIGNALED($?) ? WTERMSIG($?)+128 : WEXITSTATUS($?))
} else {exec @ARGV}' cmd
Http://devel.ringlet.net/sysutils/timelimit/ adresinde bir timelimit
komut var. (GNU’yu birkaç ay öncesinden bekliyor ).timeout
timelimit -t 86400 cmd
Biri alarm()
benzeri bir mekanizma kullanır, ancak SIGCHLD
ölen çocuğun algılanması için bir işleyici (durdurulan çocukları görmezden gelir) kurar . Ayrıca, çalıştırmadan önce alarmı da iptal eder waitpid()
( SIGALRM
beklemedeyse teslimatı iptal etmez , ancak yazıldığı şekilde, bir sorun olduğunu göremiyorum) ve aramadan önce öldürür waitpid()
(bu nedenle yeniden kullanılan bir pid'i öldüremez) ).
netpipes'ın ayrıca bir timelimit
komutu var. Biri diğerlerini yıllarca ondan önce yutuyor, bir başka yaklaşımı daha alıyor, fakat durdurulan komutlar için düzgün çalışmıyor ve 1
zaman aşımına uğradığında çıkış durumunu döndürüyor .
Sorunuza daha doğrudan bir cevap olarak, şöyle bir şey yapabilirsiniz:
if [ "$(ps -o ppid= -p "$p")" -eq "$$" ]; then
kill "$p"
fi
Yani, sürecin hala bizim çocuğumuz olduğunu kontrol edin. Yine, ps
(bu sürecin durumunu alma ve kill
öldürme arasında) sürecin ölebileceği ve ihalesinin başka bir işlem tarafından yeniden kullanılabileceği küçük bir yarış penceresi vardır .
Bazı kabukları ile ( zsh
, bash
, mksh
), sen iş spesifikasyonları yerine pids geçebilir.
cmd &
sleep 86400
kill %
wait "$!" # to retrieve the exit status
Bu, yalnızca bir arka plan işi oluşturduğunuzda işe yarar (aksi halde doğru iş hedefini almak her zaman güvenilir bir şekilde mümkün değildir).
Bu bir sorunsa, sadece yeni bir kabuk örneği başlatın:
bash -c '"$@" & sleep 86400; kill %; wait "$!"' sh cmd
Bu işe yarıyor, çünkü kabuk, çocuğun ölmesi üzerine işi iş masasından kaldırıyor. Burada, herhangi bir yarış penceresi olmamalıdır, çünkü kabuğun aradığı zaman, kill()
SIGCHLD sinyali ele alınmamıştır ve iadenin yeniden kullanılması mümkün değildir (beklenmediğinden beri), ya da iş, işlem tablosundan kaldırıldı (ve kill
bir hata bildirildi). bash
's kill
o genişletmek için kendi iş tablosunu erişmeden önce en az bloklar SIGCHLD az %
sonra ve unblocks bunu kill()
.
Bu sleep
işlemin cmd
öldükten sonra da takılı kalmasını önlemek için başka bir seçenek , ile bash
veya yerine ksh93
bir boru kullanmaktır :read -t
sleep
{
{
cmd 4>&1 >&3 3>&- &
printf '%d\n.' "$!"
} | {
read p
read -t 86400 || kill "$p"
}
} 3>&1
Bu hala yarış koşullarına sahip ve sen komutun çıkış durumunu kaybedersin. Aynı zamanda cmd
fd 4'ü kapatmayacağını da varsaymaktadır .
Yarışsız bir çözümü aşağıdaki perl
gibi uygulamayı deneyebilirsiniz :
perl -MPOSIX -e '
$p = fork();
die "fork: $!\n" unless defined($p);
if ($p) {
$SIG{CHLD} = sub {
$ss = POSIX::SigSet->new(SIGALRM); $oss = POSIX::SigSet->new;
sigprocmask(SIG_BLOCK, $ss, $oss);
waitpid($p,WNOHANG);
exit (WIFSIGNALED($?) ? WTERMSIG($?)+128 : WEXITSTATUS($?))
unless $? == -1;
sigprocmask(SIG_UNBLOCK, $oss);
};
$SIG{ALRM} = sub {
kill "TERM", $p;
exit 124;
};
alarm(86400);
pause while 1;
} else {exec @ARGV}' cmd args...
(başka tür köşe kasaları ile başa çıkmak için iyileştirilmesi gerekse de).
Yarışsız başka bir yöntem ise süreç gruplarını kullanıyor olabilir:
set -m
((sleep 86400; kill 0) & exec cmd)
Bununla birlikte, söz konusu terminal cihazına G / Ç olması durumunda, işlem gruplarını kullanmanın yan etkileri olabileceğini unutmayın. Üretildiği diğer tüm ekstra işlemleri öldürmekle birlikte, ek bir faydası vardır cmd
.