बैश में कई कमांड को चलाने और चलाने का सबसे साफ तरीका क्या है?


349

मेरे पास पहले से ही एक ssh एजेंट सेट है, और मैं Bash स्क्रिप्ट में बाहरी सर्वर पर कमांड चला सकता हूं जैसे कि सामान करना:

ssh blah_server "ls; pwd;"

अब, मैं वास्तव में क्या करना चाहूंगा बाहरी सर्वर पर बहुत लंबे कमांड चलाए जा सकते हैं। उद्धरण चिह्नों के बीच इन सभी को शामिल करना काफी बदसूरत होगा, और मैं वास्तव में इससे बचने के लिए कई बार ssh'ing से बचना चाहूंगा।

तो, क्या कोई तरीका है जो मैं एक कोष्ठक या कुछ में संलग्न कर सकता हूं? मैं कुछ की तलाश में हूँ:

ssh blah_server (
   ls some_folder;
   ./someaction.sh;
   pwd;
)

असल में, मैं किसी भी समाधान के साथ खुश रहूंगा जब तक यह साफ है।

संपादित करें

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

ssh blah_server "ls some_folder; ./someaction.sh 'some params'; pwd; ./some_other_action 'other params';"

क्योंकि यह बेहद बदसूरत और पढ़ने में मुश्किल है।


2
हम्म, कैसे सर्वर पर एक स्क्रिप्ट में है और सिर्फ एक sshआह्वान के साथ इसे कॉल करने के बारे में ?
निकोलाई Fetissov 18

@Nikolai अगर आदेशों क्लाइंट पक्ष पर निर्भर करता है, वे एक खोल स्क्रिप्ट है, तो में लिखा जा सकता है scp, sshऔर रन। यह सबसे साफ तरीका होगा, मुझे लगता है।
khachik 18

6
यह एक बड़ी बैश स्क्रिप्ट का हिस्सा है, इसलिए मैं इसे अपने व्यक्तिगत कंप्यूटर पर आधे जीवित और सर्वर पर रहने वाले अन्य आधे लोगों के साथ विभाजित नहीं करूंगा और ssh के माध्यम से चलाऊंगा। यदि संभव हो तो, मैं वास्तव में इसे केवल एक स्क्रिप्ट के रूप में रखना चाहता हूं जैसे कि मेरे व्यक्तिगत कंप्यूटर से चलाया जाता है। वहाँ वास्तव में कोई साफ रास्ता नहीं है एक ssh में आदेशों का एक गुच्छा संलग्न करने के लिए?
एली

सबसे अच्छा तरीका है बैश का उपयोग नहीं करना, लेकिन पर्ल, पायथन, रूबी, आदि
सलवा

1
आप रिमोट कमांड को उद्धरणों में रखने से क्यों बचना चाहते हैं? आपके पास जितने चाहें उतने उद्धरण हैं, आपके अंदर नई कहानियाँ हो सकती हैं; और मानक इनपुट के बजाय एक स्ट्रिंग का उपयोग करने का मतलब है कि मानक इनपुट उदाहरण के लिए दूरस्थ स्क्रिप्ट पर इनपुट पढ़ने के लिए उपलब्ध है। (हालांकि यूनिक्स पर, एकल उद्धरण आमतौर पर दोहरे उद्धरणों पर पसंद किए जाते हैं, जब तक कि आपको विशेष रूप से स्ट्रिंग के कुछ का मूल्यांकन करने के लिए स्थानीय शेल की आवश्यकता न हो।)
ट्रिपल डि

जवाबों:


457

कैसे एक बैश यहाँ दस्तावेज़ के बारे में :

ssh otherhost << EOF
  ls some_folder; 
  ./someaction.sh 'some params'
  pwd
  ./some_other_action 'other params'
EOF

टिप्पणियों में @Globalz द्वारा बताई गई समस्याओं से बचने के लिए, आप (दूरस्थ साइट पर आप जो कर रहे हैं उसके आधार पर) पहली पंक्ति को बदलने के साथ दूर हो सकते हैं

ssh otherhost /bin/bash << EOF

ध्यान दें कि आप यहाँ दस्तावेज़ में परिवर्तनीय प्रतिस्थापन कर सकते हैं, लेकिन आपको मुद्दों के हवाले से निपटना पड़ सकता है। उदाहरण के लिए, यदि आप "सीमा स्ट्रिंग" (यानी EOFउपरोक्त में) उद्धृत करते हैं , तो आप चर प्रतिस्थापन नहीं कर सकते। लेकिन सीमा स्ट्रिंग को उद्धृत किए बिना, चर प्रतिस्थापित किए जाते हैं। उदाहरण के लिए, यदि आपने $NAMEअपनी शेल स्क्रिप्ट में ऊपर परिभाषित किया है, तो आप कर सकते हैं

ssh otherhost /bin/bash << EOF
touch "/tmp/${NAME}"
EOF

और यह otherhostआपके द्वारा निर्दिष्ट किए गए नाम के साथ गंतव्य पर एक फ़ाइल बनाएगा $NAME। शेल स्क्रिप्ट के बारे में अन्य नियम भी लागू होते हैं, लेकिन यहां जाने के लिए बहुत जटिल हैं।


6
यह वैसा ही दिखता है जैसा मैं चाहता हूं! यह कैसे काम करता है? क्या आप उस पृष्ठ का लिंक देंगे जो इसे समझाता है?
एली

9
+1 केवल यह सोच रहा था कि खुद - यहाँ इसके बारे में पढ़ने के लिए एक जगह है: tldp.org/LDP/abs/html/here-docs.html
bosmacs 19

14
मुझे अपने स्थानीय में भी यह आउटपुट मिलता है: छद्म टर्मिनल आवंटित नहीं किया जाएगा क्योंकि स्टडिन एक टर्मिनल नहीं है।
ग्लोबलज

14
कमांड लाइनों के विस्तार को रोकने के लिए आपके लिए शब्द (यानी पहला 'ईओएफ') उद्धृत करना महत्वपूर्ण हो सकता है । देखें: आदमी बैश | कम + / 'यहाँ दस्तावेज़'
विधानसभा

6
पॉल, मैं केवल इसका सुझाव देता हूं क्योंकि इस प्रश्न पर लगभग 200k विचारों के साथ, ऐसा लगता है कि बहुत सारे लोग यहां आ रहे हैं जब ssh के साथ स्क्रिप्टिंग कर रहे हैं। स्क्रिप्टिंग के दौरान मूल्यों को इंजेक्ट करना सामान्य है। यदि अन्य प्रश्नों और टिप्पणियों में शोर के लिए नहीं, तो मैं सिर्फ एक बनाऊंगा और अपने रास्ते पर रहूंगा, लेकिन इस स्तर पर इसे देखने की संभावना नहीं है। एक-एक फुटनोट लोगों को कुछ प्रमुख सिरदर्द बचा सकता है।
कोए

123

अपनी स्क्रिप्ट को स्थानीय रूप से संपादित करें, फिर इसे ssh, उदाहरणार्थ पाइप करें

cat commands-to-execute-remotely.sh | ssh blah_server

जहां commands-to-execute-remotely.shदिखता सूची के ऊपर की तरह है:

ls some_folder
./someaction.sh
pwd;

7
इसका बहुत बड़ा फायदा है कि आप ठीक-ठीक जानते हैं कि रिमोट स्क्रिप्ट द्वारा क्या निष्पादित किया जा रहा है - उद्धृत करने में कोई समस्या नहीं है। यदि आपको डायनामिक कमांड की आवश्यकता है, तो आप एक शेल स्क्रिप्ट का उपयोग कर सकते हैं, एक सबशेल के साथ, अभी भी ssh में पाइपिंग, यानी ( echo $mycmd $myvar ; ...) | ssh myhost- बिल्ली के उपयोग के साथ, आपको पता है कि वास्तव में ssh कमांड स्ट्रीम में क्या जा रहा है। और निश्चित रूप से स्क्रिप्ट में उप
भाग

6
क्या आप तर्कों में ऐसा कर सकते हैं commands-to-execute-remotely.sh?
इलाकासोका

1
मुझे लगता है कि यह paultomblin समाधान की तुलना में कहीं अधिक उपयोगी है। चूंकि स्क्रिप्ट को फ़ाइल खोलने के बिना किसी भी ssh सर्वर पर पुनर्निर्देशित किया जा सकता है। यह भी अधिक पठनीय है।
पैट्रिक बासुत

3
हाँ, लेकिन इको या यहाँ के दस्तावेज़ का उपयोग करना (शीर्ष उत्तर देखें): उपयोग: दूरस्थ रूप से परिभाषित चर को दूरस्थ रूप से निष्पादित करने के लिए, दूरस्थ सर्वर पर निष्पादित किसी चीज़ का आउटपुट प्राप्त करने के लिए , $localvarस्थानीय स्तर पर परिभाषित चर \$remotevarकी व्याख्या \$(something with optionnal args)करने के लिए। एक छूट जिसे आप 1 के माध्यम से ssh कर सकते हैं (या, जैसे यहाँ दिखाया गया है, कई ssh कमांड्स):echo " for remotedir in /*/${localprefix}* ; do cd \"\$remotedir\" && echo \"I am now in \$(pwd) on the remote server \$(hostname) \" ; done " | ssh user1@hop1 ssh user2@hop2 ssh user@finalserver bash
Olivier Dulac

2
हम्म ... यह इनपुट पुनर्निर्देशन का उपयोग करने से अलग कैसे है, अर्थात ssh blah_server < commands-to-execute-remotely.sh?
flow2k

41

अपने नमूना कोड से मिलान करने के लिए, आप अपने आदेशों को सिंगल या डबल qoutes के अंदर लपेट सकते हैं। उदाहरण के लिए

ssh blah_server "
  ls
  pwd
"

मुझे यह प्रारूप पसंद है, हालाँकि यह दुख की बात है कि std डेटा को एक चर में संग्रहीत करने के लिए उपयोगी नहीं है।
साइनस

1
साइनस, "स्टैड डेटा को एक चर में संग्रहीत करने" से आपका क्या मतलब है?
आंद्रेई बी

1
@ सिग्नस यह पूरी तरह से संभव है कि आप क्या वर्णन करते हैं, हालांकि आप दूरस्थ कमांड के आसपास दोहरे उद्धरण चिह्नों के बजाय एकल उद्धरणों का उपयोग करना चाहेंगे (या उन ऑपरेटरों से बच सकते हैं जिन्हें आपके स्थानीय शेल को अवरोधन से बचाने के लिए दोहरे उद्धरणों के अंदर भागने की आवश्यकता है और उन्हें प्रक्षेप करना)।
त्रिकाल

मैं इस फाइल की तरह डबल कोट्स कोड के अंदर एक कमांड नहीं डाल पा रहा हूँ। fileToRemove में एक फ़ाइल नाम होना चाहिए, लेकिन इसके बजाय एक खाली स्ट्रिंग है। क्या कुछ बच निकलने की जरूरत है?
jkonst

37

मैं दो तरीके देखता हूं:

सबसे पहले आप इस तरह से एक कंट्रोल सॉकेट बनाते हैं:

 ssh -oControlMaster=yes -oControlPath=~/.ssh/ssh-%r-%h-%p <yourip>

और अपने आदेश चलाएं

 ssh -oControlMaster=no -oControlPath=~/.ssh/ssh-%r-%h-%p <yourip> -t <yourcommand>

इस तरह से आप वास्तव में सर्वर से पुन: कनेक्ट किए बिना एक ssh कमांड लिख सकते हैं।

दूसरा, स्क्रिप्ट को गतिशील रूप से उत्पन्न करने, उसे scpआईएनजी और चलाने के लिए होगा।


20

यह निम्नानुसार भी किया जा सकता है। अपने आदेशों को एक स्क्रिप्ट में रखें, आइए इसे नाम दें-inc.sh

#!/bin/bash
ls some_folder
./someaction.sh
pwd

फ़ाइल सहेजें

अब इसे रिमोट सर्वर पर चलाएं।

ssh user@remote 'bash -s' < /path/to/commands-inc.sh

मेरे लिए कभी असफल नहीं हुआ।


मूल रूप से मैं जैसा सोच रहा था, वैसा ही! लेकिन क्यों bash -sजरूरी है?
flow2k

इसके अलावा, #!/bin/bashवास्तव में उपयोग किया जाता है?
flow2k

2
-S संगतता के लिए वहाँ है। मैन बैश -s से यदि -s विकल्प मौजूद है, या यदि विकल्प प्रसंस्करण के बाद कोई तर्क नहीं रहता है, तो मानक इनपुट से कमांड पढ़े जाते हैं। यह विकल्प संवादात्मक खोल को लागू करते समय स्थितीय मापदंडों को सेट करने की अनुमति देता है।
RJ

1
आरजे, धन्यवाद! मेरी पहली टिप्पणी के साथ, ऐसा लग रहा है कि हम बस ऐसा करते हैं ssh user@remote < /path/to/commands-inc.sh(यह मेरे लिए काम करता है)। ठीक है, मुझे लगता है कि आपका संस्करण सुनिश्चित करता है कि हम bashशेल का उपयोग करें , और कुछ अन्य शेल का नहीं - यही उद्देश्य है, है ना?
flow2k

2
धन्यवाद। हाँ, हममें से कुछ के पास पुराने नोटों और अन्य गोले के पुराने संस्करणों से हमारे नोट्स और आदतें हैं। :-)
RJ

10

सभी कमांड को स्क्रिप्ट पर रखें और इसे चलाया जा सकता है

ssh <remote-user>@<remote-host> "bash -s" <./remote-commands.sh

थोड़ा अजीब है लेकिन यह अच्छी तरह से काम करता है। और आर्ग को स्क्रिप्ट (या तो पुनर्निर्देशित होने से पहले या बाद) में पारित किया जा सकता है। जैसे 'ssh <रिमोट-यूजर> @ <रिमोट-होस्ट> "bash -s" arg1 <./ Remote-commands.sh arg2' जैसे 'ssh <रिमोट-यूजर> @ <रिमोट-होस्ट> "bash -s" - - -आरजी 1 <। / रिमोट-
कॉमैंड.श अर्ग

ऊपर एक अन्य उत्तर के साथ मेरे पास एक समान प्रश्न था, लेकिन इसमें शामिल करने का उद्देश्य क्या है bash -s?
flow2k

1
@ flow2k -s मानक इनपुट से कमांड्स पढ़ने के लिए बैश को इंगित करता है। यहाँ manपृष्ठों से विवरण हैIf the -s option is present, or if no arguments remain after option processing, then commands are read from the standard input. This option allows the positional parameters to be set when invoking an interactive shell.
जय प्रकाश

@ जयप्रकाश इसके लिए धन्यवाद, लेकिन मैं वास्तव में सोच रहा था कि क्या हम bashपूरी तरह से कमांड के साथ दूर कर सकते हैं, अर्थात ssh remote-user@remote-host <./remote-commands.sh। मैंने अपने तरीके की कोशिश की और यह काम करने लगा, हालांकि मुझे यकीन नहीं है कि यह किसी तरह से कमी है।
flow2k

@ आदमी पृष्ठों की मेरी समझ से flow2k वहाँ विकल्प के बिना कोई कमी नहीं होगी। यदि आप किसी भी तर्क पर पारित करने की कोशिश कर रहे हैं तो इसकी आवश्यकता है। - साभार
जय प्रकाश

9

एसएसएच और बाश में कई कमांड चलाएं।

एक स्ट्रिंग के भीतर अर्धविराम के साथ अलग-अलग कमांड, गूंज के लिए पारित, सभी ssh कमांड में पाइप किया गया। उदाहरण के लिए:

echo "df -k;uname -a" | ssh 192.168.79.134

Pseudo-terminal will not be allocated because stdin is not a terminal.
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sda2       18274628 2546476  14799848  15% /
tmpfs             183620      72    183548   1% /dev/shm
/dev/sda1         297485   39074    243051  14% /boot
Linux newserv 2.6.32-431.el6.x86_64 #1 SMP Sun Nov 10 22:19:54 EST 2013 x86_64 x86_64 x86_64 GNU/Linux

अर्नब, भविष्य में, कृपया बताएं कि आपका कोड संक्षेप में क्या करता है। फिर बात करते हैं कि यह कैसे काम करता है, फिर कोड में डालें। फिर कोड को एक कोड ब्लॉक में रखें ताकि पढ़ने में आसानी हो।
एरिक लेसचिंस्की

इस सवाल से, आपने बिल्कुल वही पेश किया जो ओपी बचना चाहता है: "मैं एक लाइन के साथ बैश स्क्रिप्ट नहीं चाहता, जो दिखता है ..."
jww

6

मेरे जैसे यहाँ ठोकर खाने वाले व्यक्ति के लिए - मुझे अर्धविराम और न्यूलाइन से बचने में सफलता मिली:

पहला कदम: अर्धविराम। इस तरह, हम ssh कमांड नहीं तोड़ते हैं:

ssh <host> echo test\;ls
                    ^ backslash!

दूरस्थ होस्ट / होम निर्देशिका (रूट के रूप में लॉग इन) को सूचीबद्ध किया गया है, जबकि

ssh <host> echo test;ls
                    ^ NO backslash

वर्तमान कार्य निर्देशिका को सूचीबद्ध किया।

अगला कदम: लाइन को तोड़ना:

                      v another backslash!
ssh <host> echo test\;\
ls

इसने दूरस्थ कार्यशील निर्देशिका को फिर से सूचीबद्ध किया - बेहतर स्वरूपण:

ssh <host>\
  echo test\;\
  ls

अगर वास्तव में यहाँ से बेहतर दस्तावेज़ या टूटी हुई रेखाओं के आसपास उद्धरण - ठीक है, मुझे तय करने के लिए नहीं ...

(बैश का उपयोग करके, Ubuntu 14.04 LTS।)


1
क्या आप और भी बेहतर उपयोग कर सकते हैं && और || इस तरह, भी - इको टेस्ट \ & \ & ls
मिरो क्रोपसेक

@MiroKropacek यह बहुत अच्छा है। बेहतर? इस पर निर्भर है कि आपको क्या चाहिए; दूसरे कमांड को सशर्त रूप से चलाएं , फिर हां, बिना शर्त के चलाएं (कोई फर्क नहीं पड़ता कि कोई पहले सफल या असफल हुआ), तो नहीं ...
एकॉनकागुआ

@MiroKropacek, कमांड के आसपास डबल कोट्स डालते समय मुझे && से बचना नहीं था:ssh host "echo test && ls"
not2savvy

5

मल्टीलाइन स्ट्रिंग्स और मल्टीपल बैश स्क्रिप्ट का उपयोग करके पोस्ट किए गए उत्तर मेरे काम नहीं आए।

  • लंबे मल्टीलाइन स्ट्रिंग्स को बनाए रखना मुश्किल है।
  • अलग बैश स्क्रिप्ट स्थानीय चर को बनाए नहीं रखती है।

यहां स्थानीय संदर्भ रखते हुए कई कमांड को चलाने और चलाने का एक कार्यात्मक तरीका है।

LOCAL_VARIABLE=test

run_remote() {
    echo "$LOCAL_VARIABLE"
    ls some_folder; 
    ./someaction.sh 'some params'
    ./some_other_action 'other params'
}

ssh otherhost "$(set); run_remote"

3
आप इस बारे में सोच रहे हैं जैसे कि केवल यही कारण है कि कोई व्यक्ति ऐसा करना चाहेगा, यदि वे कमांड लाइन पर बैठे हों। इस प्रश्न के अन्य सामान्य कारण भी हैं, जैसे कि वितरित वातावरणों में कमांड को निष्पादित करना जैसे कि रंडेक, जेनकिंस, आदि
चार्ल्स एडिस

5

यकीन नहीं है कि लंबे आदेशों के लिए सबसे साफ लेकिन निश्चित रूप से सबसे आसान:

ssh user@host "cmd1; cmd2; cmd3"

सादगी में सर्वश्रेष्ठ!
not2savvy

4

स्क्रिप्ट बनाने के लिए यह अच्छी तरह से काम करता है, क्योंकि आपको अन्य फ़ाइलों को शामिल करने की आवश्यकता नहीं है:

#!/bin/bash
ssh <my_user>@<my_host> "bash -s" << EOF
    # here you just type all your commmands, as you can see, i.e.
    touch /tmp/test1;
    touch /tmp/test2;
    touch /tmp/test3;
EOF

"$ (जो बैश) -s" भाग आपको दूरस्थ मशीन के बजाय स्थानीय मशीन पर बैश का स्थान देता है। मुझे लगता है कि आप इसके बजाय '$ (जो bash) -s' चाहते हैं (स्थानीय पैरामीटर प्रतिस्थापन के लिए एकल-उद्धरण)।
jsears

1
पॉल टॉम्बलिन ने 6 साल पहले बैश हियर डॉक्यूमेंट का जवाब दिया था। इस उत्तर से क्या मूल्य जोड़ा जाता है?
jww

-sध्वज, मैं उसे उद्धृत करता हूं कि आप पहली पंक्ति को बदलने के साथ दूर जाने में सक्षम हो सकते हैं ... , और मैं बस कॉल के साथ दूर जाने में सक्षम नहीं था, जो मुझे याद है।
एसजेड

4

मल्टीप्लेक्सिंग के साथ डिफ़ॉल्ट रूप से एकल ssh सत्रों का उपयोग करने के लिए अपने सिस्टम को कॉन्फ़िगर करने का सबसे आसान तरीका।

यह सॉकेट्स के लिए एक फ़ोल्डर बनाकर किया जा सकता है:

mkdir ~/.ssh/controlmasters

और फिर आपके .ssh कॉन्फ़िगरेशन में निम्न जोड़ रहा है:

Host *
    ControlMaster auto
    ControlPath ~/.ssh/controlmasters/%r@%h:%p.socket
    ControlMaster auto
    ControlPersist 10m

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

@ टर्मिनस के जवाब के लिए धन्यवाद, http://www.cyberciti.biz/faq/linux-unix-osx-bsd-ssh-multiplexing-to-speed-up-ssh-connections/ और https://en.wikibooks.org / विकी / ओपनएसएसएच / कुकबुक / मल्टीप्लेक्सिंग

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