लूप करते समय बैश में इनपुट कैसे करें और लूप समाप्त होने के बाद वेरिएबल्स को संरक्षित करें


87

बैश उपयोग करने की अनुमति देता है: cat <(echo "$FILECONTENT")

बैश भी उपयोग करने की अनुमति: while read i; do echo $i; done </etc/passwd

पिछले दो को संयोजित करने के लिए इसका उपयोग किया जा सकता है: echo $FILECONTENT | while read i; do echo $i; done

पिछले एक के साथ समस्या यह है कि यह सब-शेल बनाता है और लूप समाप्त होने के बाद चर iको किसी भी अधिक एक्सेस नहीं किया जा सकता है।

मेरा सवाल यह है कि:

इस तरह से कुछ कैसे प्राप्त करें: while read i; do echo $i; done <(echo "$FILECONTENT")या दूसरे शब्दों में: मैं कैसे सुनिश्चित कर सकता हूं कि iलूप रहते हुए?

कृपया ध्यान दें कि मैं बयान करते समय संलग्न होने से अवगत हूं {}लेकिन यह समस्या हल नहीं करता है (कल्पना करें कि आप फ़ंक्शन और रिटर्न iचर में लूप का उपयोग करना चाहते हैं )



संबंधित: stackoverflow.com/questions/37229058/… । नीचे दिए गए प्रक्रिया प्रतिस्थापन lastpipeऔर उनके पेशेवरों और विपक्ष सहित सभी विकल्पों की व्याख्या करता है ।
ivan_pozdeev

जवाबों:


115

प्रक्रिया प्रतिस्थापन के लिए सही अंकन है:

while read i; do echo $i; done < <(echo "$FILECONTENT")

iलूप में निर्दिष्ट अंतिम मूल्य तब उपलब्ध होता है जब लूप समाप्त हो जाता है। एक विकल्प है:

echo $FILECONTENT | 
{
while read i; do echo $i; done
...do other things using $i here...
}

ब्रेसिज़ एक I / O ग्रुपिंग ऑपरेशन हैं और खुद को एक सबहेल्ड नहीं बनाते हैं। इस संदर्भ में, वे एक पाइपलाइन का हिस्सा हैं और इसलिए एक उपधारा के रूप में चलाए जाते हैं, लेकिन इसका कारण है |, नहीं { ... }। आप इस प्रश्न में उल्लेख करते हैं। AFAIK, आप एक फ़ंक्शन के अंदर इन से वापसी कर सकते हैं।


बैश भी shoptबिलिन प्रदान करता है और इसके कई विकल्पों में से एक है:

lastpipe

यदि सेट किया गया है, और नौकरी नियंत्रण सक्रिय नहीं है, तो शेल मौजूदा शेल वातावरण में पृष्ठभूमि में निष्पादित नहीं की गई पाइपलाइन की अंतिम कमांड चलाता है।

इस प्रकार, स्क्रिप्ट में कुछ इस तरह का उपयोग करना sumलूप के बाद उपलब्ध मॉडिफाइड को बनाता है :

FILECONTENT="12 Name
13 Number
14 Information"
shopt -s lastpipe   # Comment this out to see the alternative behaviour
sum=0
echo "$FILECONTENT" |
while read number name; do ((sum+=$number)); done
echo $sum

कमांड लाइन पर ऐसा करने से आमतौर पर 'जॉब कंट्रोल एक्टिव नहीं होता है' की बेईमानी चलती है (यानी कमांड लाइन पर जॉब कंट्रोल एक्टिव होता है)। स्क्रिप्ट का उपयोग किए बिना यह परीक्षण विफल रहा।

इसके अलावा, गैरेथ रीस ने अपने जवाब में कहा , आप कभी-कभी यहां स्ट्रिंग का उपयोग कर सकते हैं :

while read i; do echo $i; done <<< "$FILECONTENT"

इसके लिए आवश्यकता नहीं है shopt; आप इसका उपयोग करके एक प्रक्रिया को बचाने में सक्षम हो सकते हैं।


मेरी अज्ञानता को क्षमा करो। मुझे पता है कि यह सही समाधान है और मैंने इसे उत्तर के रूप में चिह्नित किया है ताकि यह मेरे लिए काम करे। लेकिन अब जब मैं while read i; do echo $i; done < <(cat /etc/passwd); echo $iइसे चलाता हूं तो यह दो बार अंतिम पंक्ति में नहीं लौटा। क्या मैं गलत हूं?
वाकण टंका

@WakanTanka: मुझे थोड़ा प्रयोग करना था ... मेरा मानना ​​है कि उत्तर यह है कि पढ़ने में विफल रहता iहै खाली करने के लिए, इसलिए लूप के बाद प्रतिध्वनि एक खाली लाइन गूँजती है।
जोनाथन लेफ़लर

1
प्रक्रिया प्रतिस्थापन संदर्भ के लिए यश। मैं अनजान था।
20

@Wakan Tanka: आपके जैसे ही परिणाम आए, मैंने while read i; do x=$i; done < <(cat /etc/passwd); echo i=$i; echo x=$xकाम किया, // शायद उन दिनों व्यवहार में बदलाव आया?
युरेनचेन

तुम एक जीवन रक्षक हो! एक समान समाधान के लिए घंटों की तलाश में रहा। तुम्हारा ही काम है।
पैट

28

जोनाथन लेफ़लर बताते हैं कि कैसे करना है जो आप प्रक्रिया प्रतिस्थापन का उपयोग करना चाहते हैं , लेकिन एक और संभावना यहां एक स्ट्रिंग का उपयोग करना है :

while read i; do echo "$i"; done <<<"$FILECONTENT"

यह एक प्रक्रिया बचाता है।


0

यह फ़ंक्शन jpg फ़ाइलों (bash) के $ NUM बार डुप्लिकेट बनाता है

function makeDups() {
NUM=$1
echo "Making $1 duplicates for $(ls -1 *.jpg|wc -l) files"
ls -1 *.jpg|sort|while read f
do
  COUNT=0
  while [ "$COUNT" -le "$NUM" ]
  do
    cp $f ${f//sm/${COUNT}sm}
    ((COUNT++))
  done
done
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.