बैश: इंटरैक्टिव रिमोट प्रॉम्प्ट


16

मेरे पास एक स्क्रिप्ट है जो एक दूरस्थ सर्वर से जुड़ती है और जांचती है कि कुछ पैकेज स्थापित है या नहीं:

ssh root@server 'bash -s' < myscript.sh

myscript.sh:

OUT=`rpm -qa | grep ntpdate`
if [ "$OUT" != "" ] ; then
    echo "ntpdate already installed"
else
    yum install $1
fi

इस उदाहरण को सरल बनाया जा सकता है। यहाँ एक myscript2.shही समस्या है:

read -p "Package is not installed. Do you want to install it (y/n)?" choise

मेरी समस्या यह है कि बैश मेरे उत्तरों को अंतःक्रियात्मक रूप से नहीं पढ़ सकता है।

क्या उपयोगकर्ता को संकेत देने की क्षमता खोए बिना दूरस्थ रूप से स्थानीय स्क्रिप्ट निष्पादित करने का एक तरीका है?


क्या आप विस्तार से समझा सकते हैं? यह वास्तव में स्पष्ट नहीं है कि आप क्या पूछ रहे हैं? आपके कुछ और कोड मददगार होंगे।
SLM

1
सिर्फ एक FYI करें, इसका कारण यह नहीं है क्योंकि आप STDIN पर अपनी स्क्रिप्ट पास कर रहे हैं। इस प्रकार जब बैश STDIN से पढ़ने के लिए जाता है, तो इसे आपकी स्क्रिप्ट मिलती है (या कुछ भी नहीं क्योंकि यह पहले से ही पूरी स्क्रिप्ट पढ़ चुका है और कुछ भी नहीं बचा है)।
पैट्रिक

1
: उपयोगी इस से संबंधित संसाधन backreference.org/2011/08/10/...
SLM

जवाबों:


22

कुछ इस तरह की कोशिश करो:

$ ssh -t yourserver "$(<your_script)"

-tबलों एक tty आवंटन, $(<your_script)पूरी फ़ाइल पढ़ता है और इस मामलों में करने के लिए एक तर्क के रूप में सामग्री से गुजरता sshहै, जो दूरस्थ उपयोगकर्ता के खोल द्वारा निष्पादित किया जाएगा।

यदि स्क्रिप्ट को मापदंडों की आवश्यकता है, तो स्क्रिप्ट के बाद उन्हें पास करें:

$ ssh -t yourserver "$(<your_script)" arg1 arg2 ...

मेरे लिए काम करता है, यकीन है कि अगर यह सार्वभौमिक नहीं है।


3
यह वही है जो मैं देख रहा था, धन्यवाद!
एंथनी अननिच

अच्छा समाधान है, लेकिन क्या your scriptआप अपने जवाब में उपयोग किए गए वाक्यविन्यास के लाभों को बनाए रखते हुए, एक तर्क को पारित करने का एक तरीका है ? में ssh -t yourserver "$(<your_script --some_arg)"सिर्फ परिणाम का उपयोग करना bash: --some_arg: command not found
संपाब्लोकपर

1
@sampablokuper: कोशिशssh ... $(<script) script_arg1 script_arg2 ...
Mat

@ मेत, धन्यवाद, डब्ल्यूएफएम :) शायद यह आपके उत्तर के शरीर में जोड़ सकता है?
sampablokuper

3

आपकी समस्या यह है कि sshरिमोट मशीन पर एक लॉगिन, गैर-इंटरैक्टिव शेल शुरू होता है। स्पष्ट आसान समाधान स्क्रिप्ट को दूरस्थ सर्वर पर कॉपी करना और वहां से चलाना होगा:

scp myscript.sh root@server:/tmp && ssh root@server /tmp/myscript.sh

यदि कॉपी करना किसी भी कारण से एक विकल्प नहीं है, तो मैं स्क्रिप्ट को पहले कनेक्ट करने और जांचने के लिए संशोधित करूंगा कि $1क्या स्थापित है, तो फिर से कनेक्ट करें और आवश्यक रूप से इंस्टॉल करें:

OUT=$(ssh root@server rpm -qa | grep "$1");
if [ "$OUT" != "" ] ; then
    echo "$1 already installed"
else
   read -p "Package $1 is not installed. Do you want to install it (y/n)?" choice
   if [ "$choice" -eq "y" ]; then
       ssh root@server yum install "$1"
   fi
fi

यही मैं डरता था। Ssh से कनेक्शन सबसे लंबा ऑपरेशन है और मैं इससे बचने की कोशिश कर रहा था।
एंथनी अननिच

@AnthonyAnanich आप मास्टर कनेक्शन सेट करके कनेक्शन स्थापना समय बचा सकते हैं ।
गिल्स एसओ- बुराई को रोकना '

@ गिल्स मैं सुझाव देने के बारे में सोच रहा था लेकिन मुझे लगा कि यह मेरे सुझाव के साथ काम नहीं करेगा। यदि 1 ssh कनेक्शन मास्टर के रूप में कार्य करता है, तो इसे $OUT=$(ssh root@server rpm -qa | grep "$1");बाहर निकलने के बाद बंद कर दिया जाएगा और फिर दूसरा कनेक्शन पहले की तरह अधिक समय लेगा। क्या मै गलत हु?
terdon

1
जैसे @terdon भागो कुछ ssh -M foo.example.com sleep 99999999या ssh -M foo.example.com read <somefifoमास्टर के रूप में और यह स्पष्ट रूप से मारने (साथ killया echo done >somefifo) यह करने के बाद।
गिल्स एसओ-

0

यहाँ एक अच्छी व्याख्या है

इसलिए मैंने स्क्रिप्ट को अपना लिया

hostname
echo -n "Make your choice :"
read choice
echo "You typed " ${choice}
echo done

और यह काम नहीं किया।

इसलिए मैंने ssh पर स्थानीय पुनर्निर्देशन से बचने के लिए स्क्रिप्ट को रिमोट में स्थानांतरित कर दिया। (मेरे आदेश एक फ़ाइल में हैं जिसका नाम f है )

cat f | ssh user@remotehost.com 'cat >remf'
ssh user@remotehost bash remf

यह काम किया। यहाँ उत्पादन है:

christian@clafujiu:~/tmp$ ssh localhost bash tmp/f
christian@localhost's password: 
Linux clafujiu 2.6.32-52-generic #114-Ubuntu SMP Wed Sep 11 19:00:15 UTC 2013 i686 GNU/Linux
Sun Nov 10 14:58:56 GMT 2013
Make your choice :abc
You typed  abc
done

जैसा कि @terdon ने उल्लेख किया है कि मूल रूप से स्थानीय स्क्रिप्ट को दूरस्थ रूप से चलाने के लिए था, रिमोट कॉपी को स्वचालित किया जा सकता है, यह केवल एक लाइन पर सभी का एक उदाहरण है।

REMID=`cat f |ssh user@remotehost 'cat > remf_$$; echo $$'` ;ssh root@redtoadservices.com "bash remf_${REMID} ; rm -v remf_${REMID}"

2
यह "काम" कैसे हुआ? क्या आपने इस स्क्रिप्ट bash -s < script.shको ओपी की तरह चलाया ? क्या आप इसे जोड़ने के बजाय अपने उत्तर में स्पष्टीकरण शामिल कर सकते हैं?
terdon

उफ़, इसलिए खेद है कि मैं कुछ महत्वपूर्ण जोड़ना भूल गया। मैंने स्थानीय पुनर्निर्देशन से बचने के लिए स्क्रिप्ट को रिमोट पर भी कॉपी किया। मैं इसे स्पष्ट करने के लिए अपने उत्तर के लिए अपील करूंगा।
X Tian

1
यदि आप स्क्रिप्ट की नकल करते हैं तो समस्या दूर हो जाती है। ओपी का मुद्दा यह है कि वह दूरस्थ रूप से चल रही एक स्थानीय स्क्रिप्ट को इंटरैक्टिव इनपुट देने की कोशिश कर रहा है। निश्चित रूप से यह आप की नकल पर चलेगा। ओपी इस स्क्रिप्ट को रिमोट सर्वर से कनेक्ट करते समय चलाना चाहता है, संभवतः कई रिमोट सर्वर से। मुझे संदेह है कि जब तक आप इसे स्वचालित नहीं करेंगे, तब तक इसे कॉपी करना व्यावहारिक है।
terdon

0

मैंने अतीत में कई बार इस समस्या के समाधान के लिए खोज की है, हालांकि पूरी तरह से संतोषजनक नहीं है। Ssh में पाइपिंग आपकी अन्तरक्रियाशीलता खो देता है। दो कनेक्ट (scp / ssh) धीमा है, और आपकी अस्थायी फ़ाइल को आसपास पड़ा रह सकता है। और कमांड लाइन पर पूरी स्क्रिप्ट अक्सर नरक से बचने में समाप्त होती है।

हाल ही में मैंने पाया कि कमांड लाइन बफर आकार आमतौर पर काफी बड़ा होता है ('getconf ARG_MAX> 2MB जहां मैंने देखा था)। और इससे मुझे यह सोचने को मिला कि मैं इसका उपयोग कैसे कर सकता हूं और भागने के मुद्दे को कम कर सकता हूं।

परिणाम है:

ssh -t <host> /bin/bash "<(echo "$(cat my_script | base64 | tr -d '\n')" | base64 --decode)" <arg1> ...

या यहाँ एक दस्तावेज़ और बिल्ली का उपयोग कर:

ssh -t <host> /bin/bash $'<(cat<<_ | base64 --decode\n'$(cat my_script | base64)$'\n_\n)' <arg1> ...

मैंने पूरी तरह से काम करने वाले BASH उदाहरण स्क्रिप्ट का निर्माण करने के लिए इस विचार पर विस्तार किया है sshxजो मनमानी लिपियों (न केवल BASH) को चला सकता है, जहां तर्कों को स्थानीय इनपुट फ़ाइलों को भी ssh पर किया जा सकता है। देखें यहाँ


दिलचस्प है, लेकिन यह कैसे और / या है जब यह मैट के जवाब से बेहतर है ?
स्कॉट

1
मैट का उत्तर एक अच्छा फर्स्ट पास है (जिसका मैं अक्सर उपयोग करता हूं), हालांकि यह मनमाने ढंग से सामग्री की एक स्क्रिप्ट को संभाल नहीं सकता है, जैसे कि "पात्रों को बचाना होगा। और यह भी BASH लिपियों तक ही सीमित है। मेरा समाधान किसी भी स्थापित स्क्रिप्टिंग भाषा की किसी भी स्क्रिप्ट सामग्री के लिए एक सामान्य मामला है। इसके अलावा, sshx में मैं आगे क्रमिक तर्क फ़ाइलों को प्रदर्शित करता हूं, जो कि बहुत कम है।
SourceSimian

(1) क्या आप एक स्क्रिप्ट का MCVE पोस्ट कर सकते हैं जिसके लिए Mat का उत्तर विफल रहता है (और आपका काम करता है)? (२) देखें कि "गूंज $ (सामान)" या "गूंज` सामान 'के साथ क्या गलत है?  आपके echo "$(cat my_script | base64)" | base64 --decodeबराबर (-इश) cat my_script | base64 | base64 --decodeदिखता है, जो कि एक नो-ऑप की तरह दिखता है।
स्कॉट

हाय @Scott। (१): लिपि पर विचार करें echo "ARG1=$1, USER=$USER, END":। क) $ ssh host "$(<my_bash)" foo-> ARG1=, USER=user, END foo। ख) $ ssh host bash "<(echo $(cat my_bash|base64) | base64 --decode)" foo-> ARG1=foo, USER=user, END। यहाँ (ए) प्रभावी रूप से चल रहा है: bash -c $'#!/bin/bash\necho "ARG1=$1, USER=$USER, END" foo'या कुछ इसी तरह। नोट करें कि arg काम नहीं करता है। जहां (बी) चल रहा है bash <(echo IyEvY...5EIgo= | base64 --decode) foo:। (2) मैंने परिवहन एन्कोडिंग के रूप में बेस 64 का उपयोग किया।
SourceSimian
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.