पहली पंक्ति के बाद लूप लाइन पढ़ते समय शेल स्क्रिप्ट बंद हो जाती है


107

मेरे पास निम्नलिखित शेल स्क्रिप्ट है। उद्देश्य लक्ष्य फ़ाइल की प्रत्येक पंक्ति (जिसका पथ स्क्रिप्ट में इनपुट पैरामीटर है) के माध्यम से लूप करना है और प्रत्येक पंक्ति के विरुद्ध काम करना है। अब, ऐसा लगता है कि लक्ष्य फ़ाइल में केवल पहली पंक्ति के साथ काम करना है और उस पंक्ति के संसाधित होने के बाद रुक जाता है। क्या मेरी स्क्रिप्ट में कुछ भी गलत है?

#!/bin/bash
# SCRIPT: do.sh
# PURPOSE: loop thru the targets 

FILENAME=$1
count=0

echo "proceed with $FILENAME"

while read LINE; do
   let count++
   echo "$count $LINE"
   sh ./do_work.sh $LINE
done < $FILENAME

echo "\ntotal $count targets"

में do_work.sh, मैं कुछ sshकमांड चलाता हूँ ।


1
आपकी स्क्रिप्ट ठीक है, लेकिन do_work.sh के साथ कुछ गड़बड़ हो सकती है
स्लीपसॉर्ट

2
हां, यह सभी इनपुट को खा सकता है, या इसे sourceकेवल और केवल बाहर निकलने के रूप में लागू किया जा सकता है exec। लेकिन यह कोड वास्तविक नहीं दिखता है, ओपी यह नोटिस करेगा कि इको को -eलाइन फीड को ठीक से प्रदर्शित करने की आवश्यकता है ...
माइकल क्रेलिन - हैकर

3
किसी भी मौके से do_work.shभागता sshहै?
डोगबैन

1
हाँ, do_work.sh कुछ ssh कमांड चलाता है। उसके बारे में कुछ खास?
bcbishop

1
बेहतर है कि आप do_work.shस्रोत दिखाएं और डिबग के do.shसाथ भी चलाएं set -x
कूला

जवाबों:


178

समस्या यह है कि कमांड do_work.shचलाता है sshऔर डिफ़ॉल्ट रूप sshसे स्टड से पढ़ता है जो आपकी इनपुट फ़ाइल है। परिणामस्वरूप, आप केवल पहली पंक्ति को संसाधित करते हुए देखते हैं, क्योंकि sshशेष फ़ाइल और आपका लूप समाप्त हो जाता है।

इसे रोकने के लिए, स्टैड के बजाय इसे पढ़ने के -nलिए अपनी sshकमांड के विकल्प को पास करें /dev/null


1
बहुत उपयोगी है, इस zsh oneliner को चलाने में मेरी मदद की: बिल्ली मेजबान | मेजबान पढ़ते हुए; ssh $ host do_something; किया
चूहा

3
@ आप अभी भी बेकारcat से बचना चाहते हैं आपको लगता है कि विशेष रूप से एक कृंतक इस से सावधान रहना होगा।
ट्रिपल जूल

while read host ; do $host do_something ; done < /etc/hostsइससे बचना होगा। यह काफी जीवन रक्षक है, धन्यवाद!
चूहा

httpieएक अन्य कमांड है जो डिफ़ॉल्ट रूप से STDIN को पढ़ता है, और एक ही व्यवहार से पीड़ित होगा जब एक बैश या फिश लूप के अंदर बुलाया जाता है। ऊपर के रूप में http --ignore-stdinमानक इनपुट का उपयोग करें या सेट करें /dev/null
रमन

12

आम तौर पर, एक वर्कअराउंड जो विशिष्ट नहीं है, sshवह किसी भी कमांड के लिए मानक इनपुट को रीडायरेक्ट करना है जो अन्यथा whileलूप के इनपुट का उपभोग कर सकता है ।

while read -r LINE; do
   let count++
   echo "$count $LINE"
   sh ./do_work.sh "$LINE" </dev/null
done < "$FILENAME"

इसके अलावा </dev/nullयहाँ महत्वपूर्ण बिंदु है (हालांकि सही उद्धरण भी कुछ महत्वपूर्ण है; यह भी देखें कि कब एक शेल चर के आसपास उद्धरण लपेटें? )। आप read -rतब तक उपयोग करना चाहते हैं जब तक कि आपको विशेष रूप से विरासत के बिना थोड़े अजीब व्यवहार की आवश्यकता न हो -r

sshकिसी अन्य sshकमांड का एक प्रकार का वर्कअराउंड, जो यह सुनिश्चित करने के लिए होता है कि किसी भी कमांड का मानक इनपुट बंधा हुआ है, जैसे कि बदलकर

ssh otherhost some commands here

इसके बजाय यहां दिए गए दस्तावेज़ से आदेशों को पढ़ें, जो आसानी से (इस विशेष परिदृश्य के लिए) sshआदेशों के मानक इनपुट को जोड़ता है:

ssh otherhost <<'____HERE'
    some commands here
____HERE

5

ssh -n विकल्प दूसरे प्रोग्राम में आउटपुट को पाइप करते समय HEREdoc का उपयोग करते समय ssh के बाहर निकलने की स्थिति की जाँच करने से रोकता है। इसलिए स्टड को प्राथमिकता के रूप में / देव / अशक्त का उपयोग किया जाता है।

#!/bin/bash
while read ONELINE ; do
   ssh ubuntu@host_xyz </dev/null <<EOF 2>&1 | filter_pgm 
   echo "Hi, $ONELINE. You come here often?"
   process_response_pgm 
EOF
   if [ ${PIPESTATUS[0]} -ne 0 ] ; then
      echo "aborting loop"
      exit ${PIPESTATUS[0]}
   fi
done << input_list.txt

इसका कोई मतलब नहीं है। <<EOFओवरराइड करता है </dev/nullपुनर्निर्देशन। <<पुनर्निर्देशन के बाद doneगलत है।
त्रिकाल

1

यह मेरे साथ हो रहा था क्योंकि मेरे पास था set -eऔर grepलूप में कोई आउटपुट नहीं था (जो एक गैर-शून्य त्रुटि कोड देता है)।

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