बैश स्क्रिप्ट में, लाइन द्वारा stdout लाइन पर कब्जा कैसे करें


26

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

# Start long command in a separated process and redirect stdout to temp file
longcommand > /tmp/tmp$$.out &

#loop until process completes
ps cax | grep longcommand > /dev/null
while [ $? -eq 0 ]
do
    #capture the last lines in temp file and determine if there is new content to analyse
    tail /tmp/tmp$$.out

    # ...

    sleep 1 s  # sleep in order not to clog cpu

    ps cax | grep longcommand > /dev/null
done

मैं जानना चाहूंगा कि क्या ऐसा करने का एक सरल तरीका है।

संपादित करें:

अपने प्रश्न को स्पष्ट करने के लिए, मैं इसे जोड़ूंगा। longcommandलाइन द्वारा प्रदर्शित करता है उसकी स्थिति लाइन प्रति सेकंड एक बार। मैं longcommandपूर्ण से पहले आउटपुट को पकड़ना चाहूंगा ।

इस तरह, मैं संभावित रूप से मार सकता हूं longcommandयदि यह मेरे द्वारा अपेक्षित परिणाम प्रदान नहीं करता है।

मैंने कोशिश की है:

longcommand |
  while IFS= read -r line
  do
    whatever "$line"
  done

लेकिन whatever(उदाहरण के लिए echo) longcommandपूरा होने के बाद ही निष्पादित होता है ।


जवाबों:


32

बस एक whileलूप में कमांड को पाइप करें । इसके लिए कई बारीकियां हैं, लेकिन मूल रूप से ( bashया किसी भी POSIX शेल में):

longcommand |
  while IFS= read -r line
  do
    whatever "$line"
  done

इसके साथ अन्य मुख्य गोच ( IFSनीचे के सामान के अलावा ) है जब आप लूप के अंदर से चर का उपयोग करने का प्रयास करते हैं जब यह समाप्त हो जाता है। ऐसा इसलिए है क्योंकि लूप वास्तव में एक सब-शेल (सिर्फ एक और शेल प्रक्रिया) में निष्पादित होता है, जिसे आप वेरिएबल से एक्सेस नहीं कर सकते हैं (यह भी समाप्त होता है जब लूप करता है, जिस बिंदु पर चर पूरी तरह से चले गए हैं। इसके चारों ओर पाने के लिए। तुम कर सकते हो:

longcommand | {
  while IFS= read -r line
  do
    whatever "$line"
    lastline="$line"
  done

  # This won't work without the braces.
  echo "The last line was: $lastline"
}

स्थापना के Hauke के उदाहरण lastpipeमें bashएक और उपाय है।

अद्यतन करें

यह सुनिश्चित करने के लिए कि आप कमांड के आउटपुट को 'जैसा कि होता है' कर रहे हैं, आप stdbufइस प्रक्रिया को ' stdoutबफ़र किए जाने के लिए ' सेट करने के लिए उपयोग कर सकते हैं ।

stdbuf -oL longcommand |
  while IFS= read -r line
  do
    whatever "$line"
  done

यह आंतरिक रूप से ब्लॉकों में इसके उत्पादन को बफर करने के बजाय पाइप में एक समय में एक पंक्ति लिखने की प्रक्रिया को कॉन्फ़िगर करेगा। खबरदार कि कार्यक्रम इस सेटिंग को आंतरिक रूप से बदल सकता है। एक समान प्रभाव unbuffer(के भाग expect) या के साथ प्राप्त किया जा सकता है script

stdbufजीएनयू और फ्रीबीएसडी सिस्टम पर उपलब्ध है, यह केवल stdioबफरिंग को प्रभावित करता है और केवल गैर-सेट्यूड, गैर-सेटगिड अनुप्रयोगों के लिए काम करता है जो गतिशील रूप से जुड़े हुए हैं (क्योंकि यह LD_PRELOAD ट्रिक का उपयोग करता है)।


@Stephane की IFS=जरूरत नहीं है bash, मैंने पिछली बार के बाद यह जाँच की।
ग्रीम

2
हाँ यही है। यदि आपको छोड़ lineदिया जाता है, तो इसकी आवश्यकता नहीं है (जिस स्थिति में परिणाम को $REPLYअग्रणी और अनुगामी रिक्त स्थान के बिना काट दिया जाता है)। प्रयास करें: echo ' x ' | bash -c 'read line; echo "[$line]"'और इससे तुलना करें echo ' x ' | bash -c 'IFS= read line; echo "[$line]"'याecho ' x ' | bash -c 'read; echo "[$REPLY]"'
स्टीफन Chazelas

@Stephane, ठीक है, कभी भी एहसास नहीं हुआ कि उस और नामांकित चर के बीच अंतर था। धन्यवाद।
ग्रीम

@Gememe मैं अपने प्रश्न में स्पष्ट नहीं हो सकता है, लेकिन मैं longcommand पूरा होने से पहले लाइन द्वारा आउटपुट लाइन को संसाधित करना चाहूंगा (यदि longcommand एक त्रुटि संदेश प्रदर्शित करता है तो जल्दी से प्रतिक्रिया करने के लिए)। मैं अपने प्रश्न को संपादित करने के लिए स्पष्ट
करूँगा

@gfrigon, अपडेट किया गया।
ग्रीम

2
#! /bin/bash
set +m # disable job control in order to allow lastpipe
shopt -s lastpipe
longcommand |
  while IFS= read -r line; do lines[i]="$line"; ((i++)); done
echo "${lines[1]}" # second line
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.