बैश स्क्रिप्ट अभी भी चल रही है, जबकि एक फ़ाइल के लिए उत्पादन की निस्तब्धता चल रही है


90

मेरे पास एक छोटी स्क्रिप्ट है, जिसे निम्नलिखित कमांड का उपयोग करके रोजाना क्रॉस्टैब कहा जाता है:

/homedir/MyScript &> some_log.log

इस विधि के साथ समस्या यह है कि some_log.log केवल MyScript के समाप्त होने के बाद बनाया गया है। मैं फ़ाइल में प्रोग्राम के आउटपुट को फ्लश करना चाहूंगा, जबकि यह चल रहा है इसलिए मैं जैसे चीजें कर सकता हूं

tail -f some_log.log

और प्रगति का ट्रैक रखें, आदि।


यदि संभव हो तो कोड का विवरण हमें देना होगा- आपकी छोटी स्क्रिप्ट वास्तव में क्या करती है ...
क्रिस्टोफ़ेड

7
अजगर लिपियों को हटाने के लिए आप "अजगर -यू" का उपयोग कर सकते हैं। पर्ल स्क्रिप्ट को अनबॉफर करने के लिए, नीचे ग्रेग हेविल का जवाब देखें। और इसी तरह ...
एलोइसी

यदि आप स्क्रिप्ट को संपादित कर सकते हैं, तो आप आमतौर पर स्क्रिप्ट के भीतर आउटपुट बफर को स्पष्ट रूप से फ्लश कर सकते हैं, उदाहरण के लिए अजगर के साथ sys.stdout.flush()
drevicko

जवाबों:


28

बैश खुद कभी भी आपके लॉग फ़ाइल में कोई आउटपुट नहीं लिखेगा। इसके बजाय, यह कमांड स्क्रिप्ट के भाग के रूप में आह्वान करता है, जब भी कोई व्यक्ति व्यक्तिगत रूप से आउटपुट लिखता है और जब भी ऐसा महसूस होता है, तब तक फ्लश कर सकता है। तो आपका सवाल वास्तव में है कि कैसे bash स्क्रिप्ट के भीतर कमांड को फ्लश करने के लिए मजबूर किया जाए, और यह इस बात पर निर्भर करता है कि वे क्या हैं।


25
मैं वास्तव में इस उत्तर को नहीं समझता।
अल्फोंस सैंटियागो

3
एक बेहतर विचार के लिए कि मानक आउटपुट इस तरह का व्यवहार क्यों करता है, stackoverflow.com/a/13933741/282728 देखें । एक संक्षिप्त संस्करण - डिफ़ॉल्ट रूप से, यदि किसी फ़ाइल पर रीडायरेक्ट किया गया है, तो स्टडआउट पूरी तरह से बफर हो गया है; यह फ्लश के बाद ही फाइल में लिखा जाता है। Stderr नहीं है - यह हर '\ n' के बाद लिखा जाता है। एक समाधान नीचे दिए गए 'उपयोगकर्ता' कमांड का उपयोग करने के लिए है, जो नीचे दिए गए प्रत्येक लाइन के अंत के बाद फ्लडआउट करने के लिए उपयोगकर्ता3258569 द्वारा अनुशंसित है।
एलेक्स

2
स्पष्ट बताते हुए, और दस साल बाद, लेकिन यह एक टिप्पणी है, एक उत्तर नहीं है, और इसे स्वीकृत उत्तर नहीं होना चाहिए।
रियलहैंडी

87

मुझे यहां इसका समाधान मिला । ओपी के उदाहरण का उपयोग करके आप मूल रूप से चलाते हैं

stdbuf -oL /homedir/MyScript &> some_log.log

और फिर आउटपुट के प्रत्येक लाइन के बाद बफर फ्लश हो जाता है। मैं अक्सर इसे nohupदूरस्थ मशीन पर लंबी नौकरी चलाने के लिए जोड़ती हूं ।

stdbuf -oL nohup /homedir/MyScript &> some_log.log

जब आप लॉग आउट करते हैं तो इस तरह आपकी प्रक्रिया रद्द नहीं होती है।


1
क्या आप कुछ प्रलेखन के लिए एक लिंक जोड़ सकते हैं stdbuf? इस टिप्पणी के आधार पर ऐसा लगता है कि यह कुछ विकृतियों पर उपलब्ध नहीं है। क्या आप स्पष्ट कर सकते हैं?
निधि मोनिका का मुकदमा

1
stdbuf -o समायोजित करता है stdout बफरिंग। अन्य विकल्प हैं -आई और -ई स्टड और स्टेडर के लिए। L लाइन बफ़रिंग सेट करता है। कोई बफर आकार या कोई बफरिंग के लिए 0 भी निर्दिष्ट कर सकता है।
सेप्पो एनारवी

5
वह लिंक अब उपलब्ध नहीं है।
जॉन-जोन्स

2
@ नीचार्टली: stdbufGNU कोरुटिल्स का हिस्सा है, प्रलेखन gnu.org पर पाया जा सकता है
Thor

मामले में यह किसी की मदद करता है, का उपयोग करें export -f my_function और फिर stdbuf -oL bash -c "my_function -args"अगर आप एक स्क्रिप्ट के बजाय एक समारोह चलाने की जरूरत है
बेनामी

29
script -c <PROGRAM> -f OUTPUT.txt

कुंजी है -f मैन स्क्रिप्ट से उद्धरण:

-f, --flush
     Flush output after each write.  This is nice for telecooperation: one person
     does 'mkfifo foo; script -f foo', and another can supervise real-time what is
     being done using 'cat foo'.

पृष्ठभूमि में चलो:

nohup script -c <PROGRAM> -f OUTPUT.txt

वाह! एक समाधान जो काम करता है busybox! (मेरा खोल बाद में जम जाता है, लेकिन जो भी हो)
विक्टर सर्जेनको

9

आप teeनिस्तब्धता की आवश्यकता के बिना फ़ाइल में लिखने के लिए उपयोग कर सकते हैं ।

/homedir/MyScript 2>&1 | tee some_log.log > /dev/null

2
यह अभी भी आउटपुट को कम करता है, कम से कम मेरे उबंटू 18.04 वातावरण में। सामग्री अंततः फ़ाइल के लिए लिखी जाती है, लेकिन मुझे लगता है कि ओपी एक विधि के लिए पूछ रहा है, जहां वे फ़ाइल को लिखने से पहले प्रगति की अधिक सटीक रूप से निगरानी कर सकते हैं, और यह विधि इसके लिए आउटपुट पुनर्निर्देशन से अधिक की अनुमति नहीं देती है कर देता है।
२०

3

यह एक फ़ंक्शन नहीं है bash, क्योंकि सभी शेल प्रश्न में फ़ाइल को खोलते हैं और फिर स्क्रिप्ट के मानक आउटपुट के रूप में फ़ाइल डिस्क्रिप्टर पास करते हैं। आपको यह सुनिश्चित करने की ज़रूरत है कि आउटपुट वर्तमान में आपके द्वारा किए गए स्क्रिप्ट से अधिक बार फ़्लश किया गया है

उदाहरण के लिए पर्ल में, यह सेटिंग द्वारा पूरा किया जा सकता है:

$| = 1;

इस बारे में अधिक जानकारी के लिए पर्लवार देखें ।


2

आउटपुट का बफरिंग इस बात पर निर्भर करता है कि आपका प्रोग्राम कैसे /homedir/MyScriptलागू किया जाता है। यदि आप पाते हैं कि आउटपुट बफ़र हो रहा है, तो आपको इसे अपने कार्यान्वयन में बाध्य करना होगा। उदाहरण के लिए, sys.stdout.flush () का उपयोग करें यदि यह एक पायथन प्रोग्राम है या यदि यह C प्रोग्राम है तो fflush (stdout) का उपयोग करें।


2

क्या यह मदद करेगा?

tail -f access.log | stdbuf -oL cut -d ' ' -f1 | uniq 

यह तुरंत stdbuf उपयोगिता का उपयोग करके access.log से अद्वितीय प्रविष्टियों को प्रदर्शित करेगा ।


एकमात्र परेशानी यह है कि stdbuf कुछ पुरानी उपयोगिता प्रतीत होती है जो नए डिस्ट्रोस पर उपलब्ध नहीं है।
ओंद्रा Oižka

.. मेरे बिजी बॉक्स में :(
कैम्पा

वास्तव में मैं stdbufइस समय उबंटू में उपलब्ध है, यह सुनिश्चित नहीं है कि मुझे यह कहां मिला है।
ओद्र kaižka

मेरे पास सेंटोस 7.5
मैक्स

1
उबंटू 18.04 में, stdbufका हिस्सा है coreutilus(साथ पाया apt-file search /usr/bin/stdbuf)।
रमनो

1

बस यहाँ कैसे देखा जाता है कि समस्या यह है कि आपको इंतजार करना होगा कि आप अपनी स्क्रिप्ट से जो प्रोग्राम चलाते हैं, उनकी नौकरी खत्म हो जाए।
यदि आपकी स्क्रिप्ट में आप पृष्ठभूमि में प्रोग्राम चलाते हैं तो आप कुछ और कोशिश कर सकते हैं।

सामान्य रूप से कॉल करने syncसे पहले आप फ़ाइल सिस्टम बफर को फ्लश करने की अनुमति देते हैं और थोड़ी मदद कर सकते हैं।

यदि स्क्रिप्ट में आप पृष्ठभूमि में कुछ प्रोग्राम शुरू करते हैं ( &), तो आप स्क्रिप्ट से बाहर निकलने से पहले इंतजार कर सकते हैं । यह कैसे आप नीचे देख सकते हैं कार्य कर सकते हैं के बारे में एक विचार है

#!/bin/bash
#... some stuffs ...
program_1 &          # here you start a program 1 in background
PID_PROGRAM_1=${!}   # here you remember its PID
#... some other stuffs ... 
program_2 &          # here you start a program 2 in background
wait ${!}            # You wait it finish not really useful here
#... some other stuffs ... 
daemon_1 &           # We will not wait it will finish
program_3 &          # here you start a program 1 in background
PID_PROGRAM_3=${!}   # here you remember its PID
#... last other stuffs ... 
sync
wait $PID_PROGRAM_1
wait $PID_PROGRAM_3  # program 2 is just ended
# ...

चूंकि waitनौकरियों के साथ-साथ PIDसंख्याओं के साथ काम करना स्क्रिप्ट के अंत में एक आलसी समाधान होना चाहिए

for job in `jobs -p`
do
   wait $job 
done

अधिक कठिन स्थिति यह है कि अगर आप कुछ ऐसा चलाते हैं जो पृष्ठभूमि में कुछ और चलाए क्योंकि आपको खोज करना है और इंतजार करना है (यदि यह मामला है) सभी बच्चे की प्रक्रिया का अंत : उदाहरण के लिए यदि आप एक डेमॉन चलाते हैं तो शायद ऐसा नहीं है इसे खत्म करने के लिए :-)

ध्यान दें:

  • प्रतीक्षा $ {!} का अर्थ है "अंतिम पृष्ठभूमि प्रक्रिया पूरी होने तक प्रतीक्षा करें" जहां अंतिम पृष्ठभूमि प्रक्रिया का $!पीआईडी ​​है। तो wait ${!}बस के बाद डाल program_2 &करने के लिए program_2इसे सीधे पृष्ठभूमि में भेजने के बिना निष्पादित करने के बराबर है&

  • की मदद से wait:

    Syntax    
        wait [n ...]
    Key  
        n A process ID or a job specification
    

1

धन्यवाद @user3258569, स्क्रिप्ट शायद एकमात्र ऐसी चीज है जो काम करती हैbusybox !

हालांकि इसके बाद खोल मेरे लिए ठंड था। कारण की तलाश में, मैंने इन बड़े लाल चेतावनियों को स्क्रिप्ट मैनुअल पेज में "एक गैर-संवादात्मक गोले में उपयोग न करें" :

scriptमुख्य रूप से इंटरैक्टिव टर्मिनल सत्रों के लिए डिज़ाइन किया गया है। जब स्टडिन एक टर्मिनल नहीं है (उदाहरण के लिए:) echo foo | script, तो सत्र लटका सकता है, क्योंकि स्क्रिप्ट सत्र के भीतर इंटरेक्टिव शेल ईओएफ को याद करता है और scriptसत्र बंद करने के लिए कोई सुराग नहीं है। देखें नोट अधिक जानकारी के लिए खंड।

सच। script -c "make_hay" -f /dev/null | grep "needle"मेरे लिए खोल ठंड था।

चेतावनी के विपरीत, मैंने सोचा था कि कोई ईओएफ echo "make_hay" | scriptपास करेगा, इसलिए मैंने कोशिश की

echo "make_hay; exit" | script -f /dev/null | grep 'needle'

और यह काम किया!

मैन पेज में चेतावनी पर ध्यान दें। यह आपके लिए काम नहीं कर सकता है।


0

stdbuf का विकल्प क्या awk '{print} END {fflush()}' मैं चाहता हूं कि ऐसा करने के लिए कोई बैश बिलियन हो । आम तौर पर यह आवश्यक नहीं होना चाहिए, लेकिन पुराने संस्करणों के साथ फाइल डिस्क्रिप्टर पर बैश सिंक्रोनाइज़ेशन बग हो सकते हैं।


-2

मुझे नहीं पता कि यह काम करेगा, लेकिन कॉलिंग के बारे में क्या sync?


1
syncएक निम्न-स्तरीय फ़ाइल सिस्टम ऑपरेशन है और आवेदन स्तर पर बफर आउटपुट के लिए असंबंधित है।
ग्रेग हेविगिल

2
syncयदि आवश्यक हो, तो किसी भी गंदे फाइल सिस्टम बफ़र्स को भौतिक संग्रहण पर लिखते हैं। यह ओएस के लिए आंतरिक है; ओएस के शीर्ष पर चलने वाले एप्लिकेशन हमेशा फाइल सिस्टम के एक सुसंगत दृश्य को देखते हैं कि डिस्क ब्लॉक भौतिक भंडारण के लिए लिखे गए हैं या नहीं। मूल प्रश्न के लिए, एप्लिकेशन (स्क्रिप्ट) संभवतः बफर में आउटपुट को एप्लिकेशन के आंतरिक भाग में बफ़र कर रहा है, और OS को पता भी नहीं चलेगा (अभी तक) कि आउटपुट वास्तव में stdout को लिखा जाना नियत है। इसलिए एक काल्पनिक "सिंक" -टाइप ऑपरेशन स्क्रिप्ट में "पहुंच" और डेटा को बाहर निकालने में सक्षम नहीं होगा।
ग्रेग हेवगिल सेप

-2

मैक ओएस एक्स में पृष्ठभूमि प्रक्रिया के साथ मुझे यह समस्या थी StartupItems। मैं इसे हल करता हूं:

अगर मैं बनाता हूं तो sudo ps auxमैं देख सकता हूंmytool लॉन्च किया गया है।

मैंने पाया कि (बफरिंग के कारण) जब मैक ओएस एक्स बन्द हो जाता है mytoolतो आउटपुट को sedकमांड में कभी भी स्थानांतरित नहीं करता है । हालांकि, अगर मैं निष्पादित करता हूं sudo killall mytool, तो mytoolआउटपुट को sedकमांड में स्थानांतरित करता है । इसलिए, जब मैक ओएस एक्स बन्द हो जाता है , तो मुझे उस पर एक stopकेस जोड़ा StartupItemsजाता है।

start)
    if [ -x /sw/sbin/mytool ]; then
      # run the daemon
      ConsoleMessage "Starting mytool"
      (mytool | sed .... >> myfile.txt) & 
    fi
    ;;
stop)
    ConsoleMessage "Killing mytool"
    killall mytool
    ;;

यह वास्तव में एक अच्छा जवाब नहीं है फ्रीमैन क्योंकि यह आपके पर्यावरण के लिए बहुत विशिष्ट है। ओपी आउटपुट को मॉनिटर करना चाहता है इसे मारना नहीं।
ग्रे

-3

यह पसंद है या नहीं यह कैसे पुनर्निर्देशन काम करता है।

आपके मामले में आपकी स्क्रिप्ट का आउटपुट (जिसका अर्थ है कि आपकी स्क्रिप्ट समाप्त हो गई है) उस फ़ाइल पर पुनर्निर्देशित कर दी गई है।

आप जो करना चाहते हैं, वह अपनी स्क्रिप्ट में उन पुनर्निर्देशन को जोड़ देता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.