timeout
यदि आपके पास इसका उपयोग करने के लिए सबसे अच्छा है तो कमांड का उपयोग करें :
timeout 86400 cmd
वर्तमान (8.23) GNU कार्यान्वयन alarm()
बच्चे की प्रक्रिया की प्रतीक्षा करते समय कम से कम उपयोग या समकक्ष काम करता है । ऐसा लगता है कि लौटने और बाहर निकलने (प्रभावी रूप से उस अलार्म को रद्द करने ) के SIGALRM
बीच वितरित होने के खिलाफ सुरक्षा नहीं है । उस छोटी खिड़की के दौरान, stderr पर संदेश भी लिख सकते हैं (उदाहरण के लिए यदि बच्चे ने एक कोर डंप किया है) जो उस दौड़ खिड़की को और अधिक बड़ा कर देगा (अनिश्चित काल के लिए यदि stderr उदाहरण के लिए एक पूर्ण पाइप है)।waitpid()
timeout
timeout
मैं व्यक्तिगत रूप से उस सीमा के साथ रह सकता हूं (जो शायद भविष्य के संस्करण में तय किया जाएगा)। timeout
सही निकास स्थिति की रिपोर्ट करने के लिए अतिरिक्त देखभाल भी करेगा, अन्य कोने के मामलों को संभालना (जैसे कि SIGALRM अवरुद्ध / स्टार्टअप पर नजरअंदाज करना, अन्य संकेतों को संभालना ...) बेहतर है कि आप शायद हाथ से करने का प्रबंधन करें।
एक सन्निकटन के रूप में, आप इसे इस 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/timelimit
पर एक आदेश है ( कुछ महीनों से GNU पूर्वसूचक करता है )।timeout
timelimit -t 86400 cmd
यह एक समान alarm()
तंत्र का उपयोग करता है, लेकिन SIGCHLD
मरने वाले बच्चे का पता लगाने के लिए एक हैंडलर स्थापित करता है । यह चलने से पहले अलार्म को भी रद्द कर देता है waitpid()
( SIGALRM
यदि यह लंबित होने पर डिलीवरी रद्द नहीं करता है , लेकिन जिस तरह से यह लिखा गया है, मैं इसे समस्या नहीं देख सकता) और कॉल करने से पहले मारता है waitpid()
(इसलिए पुन: उपयोग नहीं किया गया पीआईडी को नहीं मार सकता )।
netpipes में एक timelimit
कमांड भी है । वह दशकों से अन्य सभी को पहले से ही बताता है, फिर भी एक और दृष्टिकोण लेता है, लेकिन रोकी गई कमांड के लिए ठीक से काम नहीं करता है और 1
समय समाप्त होने पर बाहर निकलने की स्थिति देता है ।
आपके प्रश्न के अधिक प्रत्यक्ष उत्तर के रूप में, आप कुछ ऐसा कर सकते हैं:
if [ "$(ps -o ppid= -p "$p")" -eq "$$" ]; then
kill "$p"
fi
यही है, जांच लें कि प्रक्रिया अभी भी हमारा बच्चा है। फिर, एक छोटी दौड़ खिड़की है ( ps
उस प्रक्रिया की स्थिति को पुनः प्राप्त करने और kill
इसे मारने के बीच में ) जिसके दौरान यह प्रक्रिया मर सकती है और किसी अन्य प्रक्रिया द्वारा इसका उपयोग पुन: उपयोग किया जा सकता है।
कुछ गोले के साथ ( zsh
, bash
, mksh
), आप पीआईडी की बजाय काम चश्मा पारित कर सकते हैं।
cmd &
sleep 86400
kill %
wait "$!" # to retrieve the exit status
यह केवल तभी काम करता है जब आप केवल एक बैकग्राउंड जॉब करते हैं (अन्यथा सही जॉबस्पेक प्राप्त करना हमेशा मज़बूती से संभव नहीं होता है)।
यदि यह समस्या है, तो एक नया शेल उदाहरण शुरू करें:
bash -c '"$@" & sleep 86400; kill %; wait "$!"' sh cmd
वह काम करता है क्योंकि शेल बच्चे को मरने पर नौकरी की मेज से हटा देता है। यहां, शेल कॉल के बाद से कोई रेस विंडो नहीं होनी चाहिए kill()
, या तो SIGCHLD सिग्नल को संभाला नहीं गया है और पिड का पुन: उपयोग नहीं किया जा सकता है (क्योंकि इसका इंतजार नहीं किया गया है), या इसे हैंडल किया गया है और आगे नौकरी को प्रक्रिया तालिका से हटा दिया गया है (और kill
एक त्रुटि की रिपोर्ट करेगा)। bash
's kill
कम से कम ब्लॉक SIGCHLD पर इससे पहले कि यह विस्तार करने के लिए अपना काम तालिका तक पहुँचता है %
के बाद और यह अनब्लॉक करता kill()
।
एक अन्य विकल्प यह है कि मरने के sleep
बाद भी इस प्रक्रिया को इधर-उधर लटकने से बचाया cmd
जा सकता है, bash
या इसके बजाय ksh93
एक पाइप का उपयोग read -t
करना है sleep
:
{
{
cmd 4>&1 >&3 3>&- &
printf '%d\n.' "$!"
} | {
read p
read -t 86400 || kill "$p"
}
} 3>&1
वह अभी भी दौड़ की स्थिति है, और आप कमांड की निकास स्थिति खो देते हैं। यह भी मानता cmd
है कि अपने fd 4 को बंद नहीं करता है।
आप दौड़-मुक्त समाधान लागू करने की कोशिश कर सकते हैं perl
जैसे:
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...
(हालांकि अन्य प्रकार के कोने के मामलों को संभालने के लिए इसे सुधारने की आवश्यकता होगी)।
एक और दौड़-मुक्त विधि प्रक्रिया समूहों का उपयोग कर सकती है:
set -m
((sleep 86400; kill 0) & exec cmd)
हालाँकि, ध्यान दें कि यदि किसी टर्मिनल डिवाइस में I / O शामिल है, तो प्रक्रिया समूहों का उपयोग करने के दुष्प्रभाव हो सकते हैं। हालांकि इसका अतिरिक्त लाभ है कि सभी अन्य अतिरिक्त प्रक्रियाओं को मार डाला गया है cmd
।