SSH के माध्यम से `cd` कमांड काम क्यों नहीं करता है?


41

मैं SSH के माध्यम से कुछ फ़ाइलों का बैकअप लेने की कोशिश कर रहा था, लेकिन tarमैं जो चाहता था, उसके बदले मुझे अपना होम फोल्डर मिल गया। मैंने कुछ और परीक्षण किया और यह इसके लिए उबलता है:

ssh root@server /bin/sh -c "cd /boot && ls -l"

मेरे आश्चर्य की सूची फाइलों में /rootनहीं है /boot। लेकिन अगर मैं /bin/shएक टर्मिनल से पूरी कमांड चलाता हूं तो यह ठीक cdसे /bootफाइलों को प्रिंट और प्रिंट करता है।

यहाँ क्या हो रहा है?


1
जब तक यह एक उदाहरण नहीं है, आप इसका उपयोग क्यों नहीं कर रहे हैं ssh root@server /bin/sh -c "ls -l /boot"?
संकोची

यह अजीब बात है आपने पूछा। मैंने ऐसा करने की कोशिश की, टिप्पणी करने से पहले और अभी भी निर्देशिका लिस्टिंग नहीं मिली।
23

2
@demure क्योंकि मैं वास्तव में टार चाहता था, और टार / बूट में परिणाम में बूट पथ शामिल होगा, जो मुझे नहीं चाहिए
Ambroz Bizjak

जवाबों:


35

ssh आपको दूरस्थ कमांड पर निष्पादित करने के लिए पारित किए जाने वाले तर्कों की एक श्रृंखला के रूप में, जैसा कि आपने किया है, ठीक-ठीक निर्दिष्ट नहीं होने देता। इसके बजाय यह सभी तर्कों को एक स्ट्रिंग में बदल देता है और उन्हें एक दूरस्थ शेल के माध्यम से चलाता है। यह मेरी राय में ssh में एक प्रमुख डिजाइन दोष के रूप में बाहर खड़ा है ... यह ज्यादातर तरीकों से एक अच्छी तरह से व्यवहार किया गया यूनिक्स उपकरण है, लेकिन जब यह एक कमांड को निर्दिष्ट करने का समय आता है तो इसे एक argv के बजाय एक एकल अखंड स्ट्रिंग का उपयोग करने के लिए चुना जाता है, जैसे यह MSDOS या कुछ और के लिए डिज़ाइन किया गया था!

चूंकि ssh आपके आदेश को एक स्ट्रिंग के रूप में पारित करेगा sh -c, इसलिए आपको अपना स्वयं प्रदान करने की आवश्यकता नहीं है sh -c। जब आप करते हैं, तो परिणाम होता है

sh -c '/bin/sh -c cd /boot && ls -l'

मूल उद्धरण के साथ खो गया। इसलिए आदेशों को अलग किया &&जाता है:

`/bin/sh -c cd /boot`
`ls -l`

उनमें से पहला कमांड पाठ "सीडी" और $0= के साथ एक शेल चलाता है "boot"। "सीडी" कमांड सफलतापूर्वक पूरा होता है, $0अप्रासंगिक है, और /bin/sh -cसफलता को इंगित करता है, फिर ls -lहोता है।


2
हालांकि मैं मानता हूं कि यह दुर्भाग्यपूर्ण है कि ऐसा sshव्यवहार किया जाता है, अगर ऐसा नहीं होता, तो इसे बुलाया जाना चाहिए sexec, नहीं sshsshका सुरक्षित संस्करण है rsh(जो उस संबंध में समान व्यवहार करता है) और rlogin( जब इसे कमांड लाइन से पारित नहीं किया rshजाता है rlogin)। यह सिर्फ दुर्भाग्यपूर्ण है कि यह लागू नहीं होता है rexec
स्टीफन चेज़लस

@StephaneChazelas वहाँ कभी एक rexec आदेश था? यह सिर्फ एक सी लाइब्रेरी फंक्शन है जहां तक ​​मुझे पता है। अच्छी बात हालांकि, rsh के बारे में। Rsh के लिए ड्रॉप-इन रिप्लेसमेंट होना ssh के शुरुआती दिनों में त्वरित गोद लेने की कुंजी थी, जब हर किसी के पास पहले से ही rsh का उपयोग करने वाली स्क्रिप्ट थी।

मैंने अतीत में इसका इस्तेमाल जरूर किया था। अब, यह एचपीयूएक्स पर रहा होगा, क्योंकि कई अन्य यूनियनों के पास ऐसा नहीं था, मुझे मानना ​​होगा कि हालांकि मैं इस धारणा के तहत था कि यह अधिक व्यापक था।
स्टीफन चेज़लस

धन्यवाद। यह वास्तव में मदद की, esp। चूँकि मैं ssh के साथ सुरंग बना रहा हूँ। मुझे आउटपुट के रूप में '1 && 2' प्राप्त करने के लिए ssh -t machine1 'ssh -t machine2 "echo \" 1 && 2 \ "" "करना था। इससे कुछ ही घंटे मारे गए।
घीस

यदि आप एक कमांड को ठीक से पास करना चाहते हैं, जैसे "$ @" से, तो आप इसका उपयोग कर सकते हैं: "`printf "%q " "$@"`"बैश के साथ printfएक स्ट्रिंग या स्ट्रिंग को शेल एस्केप के साथ उद्धृत करने के लिए।
सैम वाटकिंस

36

İt का उद्धरण मुद्दा। Ssh पहले से ही आप इसे एक खोल में पारित कमांड चलाता है। जब आप कई पैरामीटर पास करते हैं, तो उन्हें स्ट्रिंग बनाने के लिए बीच में एक जगह के साथ समतल किया जाता है। इसलिए जो रिमोट कमांड आप रिमोट से चला रहे हैं /bin/sh -c cd /boot && ls -l(कोई उद्धरण नहीं है, क्योंकि आपके कमांड के उद्धरण स्थानीय शेल द्वारा व्याख्या किए गए थे)।

/bin/sh -c cd /bootचलाता है /bin/shऔर इसे कमांड चलाने cdऔर सेट $0करने के लिए भी कहता है /boot। एक बार यह हो जाने के बाद, मूल शेल (द्वारा लॉन्च किया गया sshd) चलता है ls -l

आपके मामले में, बस हटा दें sh -cजो पूरी तरह से बेकार है जब तक कि आपका रिमोट शेल (जैसा कि /etc/passwdया अन्य पासवर्ड डेटाबेस में संकेत दिया गया है) इस कमांड को नहीं समझता है।

ssh root@server "cd /boot && ls -l"

यदि आपको एक अलग शेल इनवॉइस करने की आवश्यकता है, तो आपको दूरस्थ कमांड द्वारा निर्दिष्ट रिमोट शेल द्वारा विस्तार से बचाने के लिए उद्धृत करना होगा sshd। उदाहरण के लिए, यदि आपका लॉगिन शेल डैश है और आप बैश कमांड चलाना चाहते हैं:

ssh root@server 'bash -c "cd ~bob && ls -l"'

8

मुझे लगता है कि शेल के द्वारा विकल्पों को पार्स करने के तरीके के साथ यह करना अधिक है। उदाहरण के लिए, यह काम करता है:

$ ssh root@server /bin/sh -c '"cd /boot && ls -l"'

यह आपके आदेश के समान समस्या है:

$ ssh root@server /bin/sh -c 'cd /boot && ls -l'

यदि आप -vस्विच को सक्षम करते हैं तो आप sshदेख सकते हैं कि क्या हो रहा है:

पहला आदेश:

debug1: कमांड भेजना: / बिन / श-सी "सीडी / बूट और & ls -l"

दूसरा आदेश:

debug1: कमांड भेजना: / bin / sh -c cd / boot && ls -l

आमतौर पर जब sshआप के माध्यम से आदेश भेजते हैं तो उद्धरणों पर विशेष ध्यान देना होता है और कोट के भीतर उद्धरण लपेटते हैं क्योंकि विभिन्न परतें उन्हें दूर करती हैं। भेजने में भी परेशान न करें /bin/sh

एक बार जब आप sshनिम्नलिखित जैसे उद्धरणों को समझ लेते हैं, तो आप बहुत उपयोगी काम कर सकते हैं । यह रिमोट सर्वर पर कमांड चलाएगा लेकिन सिस्टम में स्थानीय रूप से उस फाइल पर रिजल्ट इकट्ठा करेगा जहां आपने sshकमांड चलाया था :

$ ssh root@server 'free -m' > /tmp/memory.status

या यह, जहाँ आप किसी निर्देशिका को दूरस्थ सर्वर पर टारगेट करते हैं और इसे स्थानीय सिस्टम पर बनाते हैं:

$ ssh remotehost 'tar zcvf - SOURCEDIR' | cat > DESTFILE.tar.gz

संदर्भ


4

आमतौर पर आपको यह निर्दिष्ट करने की आवश्यकता नहीं है कि किस शेल का उपयोग करना है। यह काम:

ssh user@host "cd /boot && pwd"

लेकिन अगर आपका डिफ़ॉल्ट शेल समस्याग्रस्त है, तो बस यह सुनिश्चित करें कि आप शेल इनवोकेशन सहित पूरी कमांड को उद्धृत करते हैं । निम्नलिखित में से कोई भी काम करता है

ssh user@host '/bin/sh -c "cd /boot && pwd"'
ssh user@host "/bin/sh -c \"cd /boot && pwd\""

ध्यान दें कि cd /boot && pwdप्रमुख परिवारों (बॉर्न, csh, आरसी) के सभी गोले में काम करते समय , /bin/sh -c "cd /boot && pwd"यदि दूरस्थ शेल उस rcपरिवार "का नहीं है, जहां विशेष नहीं है।
स्टीफन चेज़लस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.