बैश वैरिएबल में कई लाइन आउटपुट कैप्चर करना


580

मुझे एक स्क्रिप्ट 'myscript' मिली है जो निम्न आउटपुट करती है:

abc
def
ghi

एक अन्य स्क्रिप्ट में, मैं कहता हूं:

declare RESULT=$(./myscript)

और $RESULTमूल्य प्राप्त करता है

abc def ghi

क्या रिजल्ट को या तो न्यूलाइन के साथ, या '\ n' कैरेक्टर के साथ स्टोर करने का कोई तरीका है ताकि मैं इसे ' echo -e' के साथ आउटपुट कर सकूं ?


1
यह मुझे आश्चर्य है। क्या आपके पास $ (cat ./yscipt) नहीं है? अन्यथा मुझे उम्मीद थी कि यह abc, def और gi
जोहान्स स्काउब - litb

@litb: हाँ, मुझे ऐसा लगता है; आप $ (</। myscript) का भी उपयोग कर सकते हैं, जो कमांड को निष्पादित करने से बचता है।
जोनाथन लेफ़लर

2
(एनबी: ऊपर दिए गए दो टिप्पणियाँ प्रश्न के एक संशोधन का उल्लेख करते हैं , जो मैंने शुरू किया है मुझे एक स्क्रिप्ट 'myscript' मिली है , जिसमें निम्नलिखित शामिल हैं , जिसके कारण प्रश्न थे। प्रश्न का वर्तमान संशोधन ( मुझे एक स्क्रिप्ट मिली है) myscript 'जो निम्न आउटपुट करता है ) टिप्पणियों को शानदार बनाता है। हालांकि, संशोधन 2011-11-11 से है, जब तक कि दो टिप्पणियां नहीं की गईं।
जोनाथन लेफ्लर

जवाबों:


1077

वास्तव में, परिणाम में वह है जो आप चाहते हैं - प्रदर्शित करने के लिए:

echo "$RESULT"

आप जो दिखाते हैं वही आपको मिलता है:

echo $RESULT

जैसा कि टिप्पणियों में कहा गया है, अंतर यह है कि (1) चर का दोहरा-उद्धृत संस्करण ( echo "$RESULT") मूल्य के आंतरिक रिक्ति को ठीक उसी तरह से संरक्षित करता है, जैसा कि चर में दिखाया गया है - newlines, tabs, multiple blanks और all - जबकि (2 ) निर्विवाद संस्करण ( echo $RESULT) एक या एक से अधिक रिक्त स्थान, टैब और न्यूलाइन्स के प्रत्येक अनुक्रम को एक ही स्थान से बदल देता है। इस प्रकार (1) इनपुट चर के आकार को बनाए रखता है, जबकि (2) सिंगल स्पेस द्वारा अलग किए गए 'शब्दों' के साथ आउटपुट की एक बहुत लंबी लाइन बनाता है (जहां 'शब्द' नॉन-व्हाट्सएप वर्णों का एक अनुक्रम है; वहां की जरूरत है) 'किसी भी शब्द में अल्फ़ान्यूमेरिक नहीं हो)।


69
@troelskn: अंतर यह है कि (1) चर का दोहरा-उद्धृत संस्करण मूल्य के आंतरिक रिक्ति को सुरक्षित रखता है, जैसा कि यह चर, newlines, टैब, कई रिक्त स्थान और सभी में दर्शाया गया है, जबकि (2) निर्विवाद संस्करण बदलता है एक या अधिक रिक्तियाँ, टैब और एक ही स्थान के साथ newlines के प्रत्येक अनुक्रम। इस प्रकार (1) इनपुट चर के आकार को बनाए रखता है, जबकि (2) सिंगल स्पेस द्वारा अलग किए गए 'शब्दों' के साथ आउटपुट की एक बहुत लंबी लाइन बनाता है (जहां 'शब्द' नॉन-व्हाट्सएप वर्णों का एक अनुक्रम है; वहां की जरूरत है) 'किसी भी शब्द में अल्फ़ान्यूमेरिक नहीं हो)।
जोनाथन लेफ़लर

23
उत्तर को समझने में आसान बनाने के लिए: उत्तर बताता है कि गूंज "$ RESULT" नई रेखा को संरक्षित करता है, जबकि गूंज $ RESULT नहीं है।
यू शेन

यह नई स्थितियों और कुछ स्थितियों में अग्रणी स्थानों को संरक्षित करने में विफल रहता है।
CommaToast

3
@CommaToast: क्या आप उस पर विस्तार करने जा रहे हैं? अनुगामी न्यूलाइन्स खो जाती हैं; उस के आसपास एक आसान तरीका नहीं है। रिक्त स्थान - मुझे किसी भी परिस्थिति की जानकारी नहीं है जिसके तहत वे खो गए हैं।
जोनाथन लेफ़लर


90

इसके साथ एक और नुकसान यह है कि कमांड प्रतिस्थापन - $()नई स्ट्रिप्स को स्ट्रिप्स करता है। शायद हमेशा महत्वपूर्ण नहीं है, लेकिन अगर आप वास्तव में वास्तव में उत्पादन करना चाहते थे, तो आपको दूसरी पंक्ति और कुछ उद्धरण का उपयोग करना होगा:

RESULTX="$(./myscript; echo x)"
RESULT="${RESULTX%x}"

यह विशेष रूप से महत्वपूर्ण है यदि आप सभी संभव फ़ाइल नाम को संभालना चाहते हैं (गलत फ़ाइल पर काम करने की तरह अपरिभाषित व्यवहार से बचने के लिए)।


4
मुझे कुछ समय के लिए एक टूटे हुए शेल के साथ काम करना पड़ा जिसने कमांड प्रतिस्थापन से अंतिम नई रेखा नहीं निकाली (यह प्रक्रिया प्रतिस्थापन नहीं है ), और इसने लगभग सब कुछ तोड़ दिया। उदाहरण के लिए, यदि आपने किया था, तो आपको pwd=`pwd`; ls $pwd/$fileपहले एक नई पंक्ति मिली थी , /और दोहरे उद्धरण चिह्नों में नाम संलग्न करने से कोई फायदा नहीं हुआ। यह जल्दी तय हो गया था। यह ICL Perq PNX पर 1983-5 की समय सीमा में वापस आ गया था; शेल $PWDएक अंतर्निर्मित चर के रूप में नहीं था ।
जोनाथन लेफ्लर

19

यदि आप विशिष्ट लाइनों में रुचि रखते हैं, तो परिणाम-सरणी का उपयोग करें:

declare RESULT=($(./myscript))  # (..) = array
echo "First line: ${RESULT[0]}"
echo "Second line: ${RESULT[1]}"
echo "N-th line: ${RESULT[N]}"

3
यदि लाइनों में रिक्त स्थान हैं, तो यह लाइनों के बजाय फ़ील्ड (रिक्त स्थान के बीच सामग्री) की गणना करेगा।
लियाम

2
आप readarrayकमांड प्रतिस्थापन के बजाय प्रतिस्थापन का उपयोग और प्रक्रिया करेंगे readarray -t RESULT < <(./myscript>:।
chepner

15

@ L0b0 द्वारा दिए गए उत्तर के अलावा, मेरे पास वह स्थिति थी जहां मुझे स्क्रिप्ट द्वारा किसी भी अनुगामी newlines आउटपुट रखने और स्क्रिप्ट के रिटर्न कोड की जांच करने की आवश्यकता थी। और l0b0 के उत्तर के साथ समस्या यह है कि 'इको एक्स' $ रीसेट कर रहा था? शून्य पर वापस ... तो मैं इस बहुत चालाक समाधान के साथ आने में कामयाब रहा:

RESULTX="$(./myscript; echo x$?)"
RETURNCODE=${RESULTX##*x}
RESULT="${RESULTX%x*}"

यह प्यारा है, मेरे पास वास्तव में उपयोग का मामला था जहां मैं एक ऐसा die ()कार्य करना चाहता हूं जो एक मनमाना निकास कोड को स्वीकार करता है और वैकल्पिक रूप से एक संदेश है, और मैं usage ()संदेश की आपूर्ति करने के लिए एक और फ़ंक्शन का उपयोग करना चाहता था, लेकिन नए समाचारों को दरकिनार रखा गया, उम्मीद है कि यह मुझे अनुमति देता है उसके आसपास काम करो।
ड्रैगन 88

1

यहां अधिकांश समाधानों की कोशिश करने के बाद, मुझे जो सबसे आसान चीज मिली वह स्पष्ट थी - एक टेम्प फाइल का उपयोग करना। मुझे यकीन नहीं है कि आप अपने कई लाइन आउटपुट के साथ क्या करना चाहते हैं, लेकिन फिर आप इसे पढ़कर लाइन का उपयोग करके लाइन से निपट सकते हैं। केवल एक चीज के बारे में जो आप वास्तव में नहीं कर सकते हैं वह आसानी से सभी को एक ही चर में चिपका सकता है, लेकिन अधिकांश व्यावहारिक उद्देश्यों के लिए यह आसान तरीका है।

./myscript.sh > /tmp/foo
while read line ; do 
    echo 'whatever you want to do with $line'
done < /tmp/foo

अनुरोधित कार्रवाई करने के लिए त्वरित हैक:

result=""
./myscript.sh > /tmp/foo
while read line ; do
  result="$result$line\n"
done < /tmp/foo
echo -e $result

ध्यान दें कि यह एक अतिरिक्त रेखा जोड़ता है। यदि आप इस पर काम करते हैं, तो आप इसके चारों ओर कोड कर सकते हैं, मैं अभी बहुत आलसी हूं।


EDIT: जबकि यह मामला पूरी तरह से अच्छी तरह से काम करता है, इसे पढ़ने वाले लोगों को इस बात की जानकारी होनी चाहिए कि आप आसानी से लूप के अंदर अपने स्टड को स्क्वाश कर सकते हैं, इस प्रकार यह आपको एक स्क्रिप्ट देता है जो एक लाइन, क्लियर स्टड और एग्जिट को चलाएगा। जैसे शश ऐसा करेगा कि मैं सोचूं? मैंने अभी हाल ही में इसे देखा, अन्य कोड उदाहरण यहाँ: /unix/24260/reading-lines-from-a-file-with-bash-for-vs-ward

एक और बार! इस बार एक अलग फाइलहैंडल के साथ (स्टड, स्टडआउट, स्टेडर 0-2 हैं, इसलिए हम उपयोग कर सकते हैं और 3 या उससे अधिक बैश में हैं)।

result=""
./test>/tmp/foo
while read line  <&3; do
    result="$result$line\n"
done 3</tmp/foo
echo -e $result

तुम भी mktemp का उपयोग कर सकते हैं, लेकिन यह सिर्फ एक त्वरित कोड उदाहरण है। मस्कैम्प के लिए उपयोग की तरह दिखता है:

filenamevar=`mktemp /tmp/tempXXXXXX`
./test > $filenamevar

इसके बाद $ फ़ाइलनाम का उपयोग करें जैसे कि आप किसी फ़ाइल का वास्तविक नाम होगा। शायद यहाँ समझाने की ज़रूरत नहीं है लेकिन किसी ने टिप्पणी में शिकायत की।


मैंने अन्य समाधानों की भी कोशिश की, आपके पहले सुझाव से मुझे अंततः मेरी स्क्रिप्ट काम कर रही थी
करमा।

1
डाउनवोट: यह अत्यधिक जटिल है, और कई सामान्य bashनुकसान से बचने में विफल रहता है ।
त्रिकाल

हां किसी ने मुझे दूसरे दिन अजीब स्टड फाइलहैंडल समस्या के बारे में बताया और मैं "वाह" जैसा था। Lemme वास्तव में जल्दी से कुछ जोड़ें।
user1279741

बैश में, आप फ़ाइल डिस्क्रिप्टर 3 से पढ़ने के लिए readकमांड एक्सटेंशन -u 3का उपयोग कर सकते हैं
जोनाथन लेफ़लर

क्यों नहीं ... करते हैं ... किया <<(।
Myscript.sh

0

इसके बारे में कैसे, यह एक चर के लिए प्रत्येक पंक्ति पढ़ेगा और बाद में इसका इस्तेमाल किया जा सकता है! myscript आउटपुट को myscript_output नामक फ़ाइल पर पुनर्निर्देशित किया जाता है

awk '{while ( (getline var < "myscript_output") >0){print var;} close ("myscript_output");}'

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