कैसे एक सुरुचिपूर्ण तरीके से हमेशा के लिए कुछ नहीं करना है?


82

मेरे पास एक कार्यक्रम है जो उपयोगी जानकारी का उत्पादन करता है, stdoutलेकिन इससे भी पढ़ता है stdin। मैं मानक इनपुट पर कुछ भी प्रदान किए बिना इसके मानक आउटपुट को एक फ़ाइल में पुनर्निर्देशित करना चाहता हूं। अब तक, इतना अच्छा: मैं कर सकता हूँ:

program > output

और ट्टी में कुछ भी नहीं है।

हालाँकि, समस्या यह है कि मैं इसे पृष्ठभूमि में करना चाहता हूं। यदि मैं करता हूँ:

program > output &

कार्यक्रम स्थगित हो जाएगा ("निलंबित इनपुट (ट्टी इनपुट)")।

यदि मैं करता हूँ:

program < /dev/null > output &

कार्यक्रम तुरंत समाप्त हो जाता है क्योंकि यह ईओएफ तक पहुंचता है।

ऐसा लगता है कि मुझे जिस चीज की आवश्यकता है, वह उस चीज में पाइप करना programहै जो अनिश्चित समय के लिए कुछ भी नहीं करता है और नहीं पढ़ता है stdin। निम्नलिखित दृष्टिकोण काम करते हैं:

while true; do sleep 100; done | program > output &
mkfifo fifo && cat fifo | program > output &
tail -f /dev/null | program > output &

हालांकि, यह सब बहुत बदसूरत है। वहाँ है एक सुंदर तरीका हो सकता है, मानक यूनिक्स उपयोगिताओं का उपयोग कर, "कुछ नहीं करते, अनिश्चित काल के लिए" करने के लिए (व्याख्या करने के लिए man true)। मैं इसे कैसे हासिल कर सकता हूं? (यहाँ लालित्य के लिए मेरा मुख्य मानदंड: कोई अस्थायी फ़ाइलें नहीं; कोई व्यस्त-प्रतीक्षा या आवधिक वेकअप नहीं; संभव के रूप में कोई विदेशी उपयोगिताओं;)।


कोशिश करो su -c 'program | output &' user। मैं "सेवा / डेमॉन" को संभालने के लिए स्वीकार्य विधि के रूप में पृष्ठभूमि की नौकरियों के निर्माण के साथ एक समान प्रश्न पूछने वाला हूं। मैंने यह भी देखा कि मैं पुनर्निर्देशित STDERRकिए बिना भी पुनर्निर्देशित नहीं कर सकता था STDOUT। समाधान जहां प्रोग्रामए प्रोग्रामबी को भेजता STDOUTहै STDIN, फिर STDERRलॉग फ़ाइल में रीडायरेक्ट करता है:programA 2> /var/log/programA.log | programB 2> /var/log/programB.log 1> /dev/null
mbrownnyc

शायद ... su -c 'while true; do true; done | cat > ~/output &' user?
mbrownnyc

कार्यक्रम किस तरह का है?
जोहो पोर्टेला

जोआओ पोर्टेला: यह एक कार्यक्रम है जिसे मैंने लिखा है, gitorious.org/irctk
a3nm

आपने जो कार्यक्रम लिखा था, उसमें केवल एक स्विच क्यों नहीं जोड़ा गया? इसके अलावा, मेरा मानना ​​है कि यदि आप 1<&-इसके साथ स्टड बंद करते हैं तो यह आपके कार्यक्रम से बाहर निकल जाएगा?
w00t

जवाबों:


16

गोले में जो उनका समर्थन करते हैं (ksh, zsh, bash4), आप सह-प्रक्रिया केprogram रूप में शुरू कर सकते हैं ।

  • ksh: program > output |&
  • zsh, bash:coproc program > output

programइसके इनपुट के साथ पृष्ठभूमि में शुरू होता है एक से पुनर्निर्देशित pipe। पाइप का दूसरा छोर खोल के लिए खुला है।

उस दृष्टिकोण के तीन लाभ

  • कोई अतिरिक्त प्रक्रिया नहीं
  • जब आप programमर जाते हैं तो स्क्रिप्ट से बाहर निकल सकते हैं (इसके waitलिए प्रतीक्षा करें)
  • programसमाप्त हो जाएगा ( eofइसके स्टड पर प्राप्त करें यदि शेल बाहर निकलता है)।

यह काम करने के लिए लगता है और एक महान विचार की तरह लग रहा है! (निष्पक्ष होने के लिए, मैंने अपने कमांड पर पाइप करने के लिए कुछ पूछा था, शेल फीचर के लिए नहीं, लेकिन यह प्ले में केवल एक्स समस्या थी।) मैं @ पीटी के एक के बजाय इस उत्तर को स्वीकार करने पर विचार कर रहा हूं।
a3nm

1
@ a3nm, tail -f /dev/nullआदर्श नहीं है क्योंकि यह हर सेकंड रीड करता है /dev/null(लिनक्स में GNU टेल के वर्तमान संस्करण इनोटिफाई का उपयोग करके वास्तव में एक बग है )। sleep infया इसके अधिक पोर्टेबल समतुल्य sleep 2147483647एक कमांड के लिए बेहतर दृष्टिकोण हैं जो आईएमओ को कुछ भी नहीं करता है (ध्यान दें कि sleepकुछ गोले में ksh93या जैसे बनाया गया है mksh)।
स्टीफन चेज़लस

78

मुझे नहीं लगता कि आप किसी भी अधिक से अधिक सुंदर पाने जा रहे हैं

tail -f /dev/null

आपने पहले ही सुझाव दिया था (यह मानते हुए कि यह आंतरिक रूप से उपयोग करता है, कोई मतदान या वेकअप नहीं होना चाहिए, इसलिए विषम दिखने के अलावा, यह पर्याप्त होना चाहिए)।

आपको एक उपयोगिता की आवश्यकता है जो अनिश्चित काल तक चलेगी, अपने स्टडआउट को खुला रखेगा, लेकिन वास्तव में स्टडआउट के लिए कुछ भी नहीं लिखेगा, और जब इसकी गति बंद हो जाएगी तो बाहर नहीं निकलेगा। कुछ yesवास्तव में stdout को लिखता है। catबाहर निकल जाएगा जब इसकी स्टड बंद हो जाती है (या जो भी आप इसे फिर से निर्देशित करते हैं वह किया जाता है)। मुझे लगता है sleep 1000000000dकि काम हो सकता है, लेकिन tailस्पष्ट रूप से बेहतर है। मेरे डेबियन बॉक्स में एक tailfछोटा कमांड है।

एक अलग सौदा लेते हुए, कार्यक्रम को कैसे चलाया जाए screen?


मुझे tail -f /dev/nullदृष्टिकोण सबसे अच्छा लगता है और इसे पर्याप्त रूप से सुंदर लगता है, क्योंकि कमांड का उपयोग इच्छित उद्देश्य से काफी निकटता से मेल खाता है।
jw013

2
से strace tail -f /dev/nullऐसा लगता है कि tailका उपयोग करता है inotifyऔर कहा कि wakeups तरह मूर्खतापूर्ण मामलों में हो sudo touch /dev/null। यह दुखद है कि कोई बेहतर समाधान नहीं लगता है ... मुझे आश्चर्य है कि बेहतर समाधान को लागू करने के लिए सही syscall का उपयोग किया जाएगा।
a3nm

5
@ a3nm syscall होगा pause, लेकिन यह सीधे शेल इंटरफ़ेस के संपर्क में नहीं है।
गाइल्स

पीटी: मुझे इसके बारे में पता है screen, लेकिन यह परीक्षण उद्देश्यों के लिए शेल स्क्रिप्ट से प्रोग्राम की कई घटनाओं को चलाने के लिए है, इसलिए इसका उपयोग screenकरना थोड़ा कठिन है।
a3nm

3
@sillyMunky सिली मंकी, वलज का जवाब गलत है (स्टड पर अनंत शून्य भेजता है)।
पीटी

48

sleep infinity मुझे पता है कि सबसे स्पष्ट समाधान है

आप उपयोग कर सकते हैं infinityक्योंकि sleepएक अस्थायी बिंदु संख्या * को स्वीकार करता है , जो दशमलव , हेक्साडेसिमल , अनंत या NaN , के अनुसार हो सकता है man strtod

* यह POSIX मानक का हिस्सा नहीं है, इसलिए उतना पोर्टेबल नहीं है tail -f /dev/null। हालांकि, यह जीएनयू कोर्यूटिल्स (लिनक्स) और बीएसडी (मैक पर उपयोग किया जाता है) में समर्थित है (जाहिरा तौर पर मैक के नए संस्करणों पर समर्थित नहीं है - टिप्पणियां देखें)।


हाहा, यह वास्तव में एक अच्छा तरीका है। :)
a3nm

@ a3nm: धन्यवाद:) लगता है कि बीएसडी और मैक परsleep infinity भी काम होता है
ज़ाज़

एक असीम नींद की प्रक्रिया में किस तरह के संसाधन लगते हैं? सिर्फ राम?
CMCDragonkai

1
यह उत्तर दावा करता है कि sleep infinityअधिकतम 24 दिनों तक प्रतीक्षा करता है; कौन सही है?
nh2

1
@Zaz मैंने अब इस मुद्दे पर विस्तार से जांच की है। यह पता चला है कि आप शुरू में सही थे! sleepउपयोगिता है 24 दिनों तक ही सीमित नहीं ; यह सिर्फ पहला syscall है जो 24 दिनों तक सोता है, और बाद में यह इस तरह के और अधिक syscalls करेगा। मेरी टिप्पणी यहाँ देखें: stackoverflow.com/questions/2935183/…
nh2

19
sleep 2147483647 | program > output &

हां, 2^31-1एक परिमित संख्या है, और यह हमेशा के लिए नहीं चलेगी , लेकिन मैं आपको $ 1000 दूंगा जब नींद अंततः बाहर निकल जाएगी। (संकेत: हममें से एक तब तक मर चुका होगा।)

  • कोई अस्थायी फ़ाइलें नहीं; चेक।
  • कोई व्यस्त-प्रतीक्षा या आवधिक वेकअप; चेक
  • कोई विदेशी उपयोगिताओं नहीं; चेक।
  • जितना संभव हो उतना कम। ठीक है, यह कम हो सकता है।

5
bash: स्लीप $ ((64 # 1 _____)) | कार्यक्रम> आउटपुट और
डिएगो टॉरेस मिलानो

68 वर्षों तक यह सोता है, यह 98 सदियों तक सोता है : sleep 2147483647d...
agc

9

आप एक ऐसा बाइनरी बना सकते हैं जो इसके साथ बस इतना ही करे:

$ echo 'int main(){ pause(); }' > pause.c; make pause

5

मानक यूनिक्स उपयोगिताओं का उपयोग करने के लिए यहां एक और सुझाव है , "कुछ भी नहीं, अनिश्चित काल के लिए"

sh -c 'kill -STOP $$' | program > output

यह तुरंत भेजे जाने वाले एक शेल को फायर करता है SIGSTOP, जो प्रक्रिया को निलंबित करता है। यह आपके प्रोग्राम के लिए "इनपुट" के रूप में उपयोग किया जाता है। का पूरक SIGSTOPहै SIGCONT, यानी अगर आपको पता है कि शेल में PID 12345 है तो आप kill -CONT 12345इसे जारी रख सकते हैं।


2

लिनक्स पर, आप कर सकते हैं:

read x < /dev/fd/1 | program > output

लिनक्स पर, खोलने / dev / fd / x जहां x एक पाइप के लेखन छोर के लिए एक फाइल डिस्क्रिप्टर है, आपको पाइप का रीडिंग एंड मिलता है, इसलिए यहां प्रोग्राम के स्टैड पर समान है। इसलिए मूल रूप से, readकभी नहीं लौटेगा, क्योंकि केवल एक चीज जो उस पाइप को लिख सकती है वह स्वयं है, और readकुछ भी आउटपुट नहीं करता है।

यह FreeBSD या Solaris पर भी काम करेगा, लेकिन किसी अन्य कारण से। वहाँ, खोलने / dev / fd / 1 से आपको वही संसाधन प्राप्त होते हैं जो fd 1 पर खुले होते हैं जैसा कि आप अपेक्षा करते हैं और जैसा कि लिनक्स के अलावा अधिकांश सिस्टम करते हैं, इसलिए पाइप का लेखन अंत। हालांकि, FreeBSD और Solaris पर, पाइपों को द्विदिश किया जाता है। इसलिए जब तक programवह अपने स्टड (कोई एप्लिकेशन नहीं करता है) को नहीं लिखता, readतब तक पाइप की उस दिशा से पढ़ने के लिए कुछ नहीं मिलेगा।

उन प्रणालियों पर जहां पाइप द्विदिश नहीं हैं, readलेखन-केवल फ़ाइल विवरणक से पढ़ने का प्रयास करते समय संभवतः एक त्रुटि के साथ विफल हो जाएगा। यह भी ध्यान दें कि सभी सिस्टम में नहीं है /dev/fd/x


बहुत अच्छा! वास्तव में मेरे परीक्षणों में आपको xबैश की जरूरत नहीं है ; आगे zsh के साथ आप बस कर सकते हैं readऔर यह काम करता है (हालांकि मुझे समझ नहीं आता क्यों!)। क्या यह चाल लिनक्स-विशिष्ट है, या यह सभी * निक्स सिस्टम पर काम करता है?
a3nm

@ a3nm, यदि आप readअकेले करते हैं, तो यह स्टड से पढ़ेगा। इसलिए यदि यह टर्मिनल है, तो यह तब तक पढ़ेगा जब तक आप एंटर नहीं करते हैं।
स्टीफन चेजलस

यकीन है, मैं समझता हूँ कि क्या पढ़ता है। मुझे समझ में नहीं आ रहा है कि एक पृष्ठभूमि वाली प्रक्रिया में पढ़ने के साथ टर्मिनल से पढ़ना बैश के साथ अवरुद्ध है, लेकिन ज़श के साथ नहीं।
a3nm

@ a3nm, मुझे यकीन नहीं है कि तुम क्या मतलब है। आप क्या मतलब है आप बस कर सकते हैं readऔर यह काम करता है ?
स्टीफन चेज़लस

मैं कह रहा हूं कि zsh के साथ आप बस कर सकते हैं read | program > outputऔर यह उसी तरह से काम करता है जैसा आपने सुझाया था। (और मैं क्यों नहीं मिलता।)
a3nm

0

स्टीफन चेज़लस का read समाधान मैक ओएस एक्स पर काम करता है और यदि रीडिंग एफडी खुल जाता है /dev/fd/1

# using bash on Mac OS X
# -bash: /dev/fd/1: Permission denied
read x </dev/fd/1 | cat >/dev/null
echo ${PIPESTATUS[*]}   #  1 0

exec 3<&- 3</dev/fd/1
read x 0<&3 | cat >/dev/null
echo ${PIPESTATUS[*]}   #  0 0

tail -f /dev/nullस्क्रिप्ट में मारने में सक्षम होने के लिए (SIGINT के साथ, उदाहरण के लिए) tailकमांड को पृष्ठभूमि देना आवश्यक है और wait

#!/bin/bash
# ctrl-c will kill tail and exit script
trap 'trap - INT; kill "$!"; exit' INT
exec tail -f /dev/null & wait $!

-2

/dev/zeroमानक इनपुट के रूप में पुनर्निर्देशित करें !

program < /dev/zero > output &

9
यह उनके कार्यक्रम को शून्य-बाइट्स की अनंत संख्या देगा ... जो दुख की बात है कि यह व्यस्त-पाश बना देगा।
23

1
यह सही जैंडर नहीं है, / देव / शून्य कभी बंद नहीं होगा, पाइप श्रृंखला को खुला रखना। हालांकि, पोस्टर का कहना है कि वह स्टड में नहीं है, इसलिए किसी भी शून्य को कभी भी कार्यक्रम में स्थानांतरित नहीं किया जाएगा। यह एक व्यस्त लूप नहीं है, यह एक शुद्ध प्रतीक्षा है।
सिलीमुनकी

2
क्षमा करें, ओपी स्टड का उपयोग करता है, इसलिए यह उसके इनपुट को मिटा देगा और / dev / शून्य से आरेखण करेगा। मुझे अगली बार दो बार पढ़ना चाहिए! यदि ओपी स्टडिन का उपयोग नहीं कर रहा था, तो यह सबसे सुरुचिपूर्ण समाधान होगा जिसे मैंने देखा है, और एक व्यस्त प्रतीक्षा नहीं होगी।
मूर्खतापूर्ण जूल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.