En iyisi, timeoutkomutun 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ış SIGALRMarası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()timeouttimeout
Şahsen ben bu sınırlama ile yaşayabilirim (ki bu muhtemelen gelecekteki bir versiyonda düzeltilecektir). timeoutayrı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 timelimitkomut 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()( SIGALRMbeklemedeyse 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 timelimitkomutu 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 1zaman 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 killbir hata bildirildi). bash's killo genişletmek için kendi iş tablosunu erişmeden önce en az bloklar SIGCHLD az %sonra ve unblocks bunu kill().
Bu sleepişlemin cmdöldükten sonra da takılı kalmasını önlemek için başka bir seçenek , ile bashveya yerine ksh93bir boru kullanmaktır :read -tsleep
{
{
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 cmdfd 4'ü kapatmayacağını da varsaymaktadır .
Yarışsız bir çözümü aşağıdaki perlgibi 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.