मुझे नहीं लगता कि ssh
शेल को शामिल किए बिना क्लाइंट से सर्वर तक एक कमांड को पारित करने के लिए किसी भी देशी तरीके का कोई भी कार्यान्वयन है ।
अब, चीजें आसान हो सकती हैं यदि आप दूरस्थ शेल को केवल एक विशिष्ट दुभाषिया चलाने के लिए कह सकते हैं (जैसे sh
, जिसके लिए हम अपेक्षित सिंटैक्स जानते हैं) और कोड को किसी अन्य माध्यम से निष्पादित करने के लिए देते हैं।
यह अन्य मतलब उदाहरण के लिए हो सकता है मानक इनपुट या एक पर्यावरण चर ।
जब न तो उपयोग किया जा सकता है, मैं नीचे एक हैकी तीसरा समाधान प्रस्तावित करता हूं।
स्टड का उपयोग करना
यदि आपको दूरस्थ कमांड पर कोई डेटा फीड करने की आवश्यकता नहीं है, तो यह सबसे आसान उपाय है।
यदि आप जानते हैं कि रिमोट होस्ट में एक xargs
कमांड है जो -0
विकल्प का समर्थन करता है और कमांड बहुत बड़ी नहीं है, तो आप कर सकते हैं:
printf '%s\0' "${cmd[@]}" | ssh user@host 'xargs -0 env --'
उस xargs -0 env --
कमांड लाइन की व्याख्या उन सभी शेल परिवारों के साथ की जाती है। xargs
स्टड पर तर्कों की शून्य-सीमांकित सूची को पढ़ता है और उन लोगों को तर्क के रूप में पास करता है env
। यह पहला तर्क मानता है (कमांड नाम) में =
वर्ण नहीं हैं ।
या आप सिंटैक्स sh
का उपयोग करके प्रत्येक तत्व को उद्धृत करने के बाद दूरस्थ होस्ट पर उपयोग कर सकते हैं sh
।
shquote() {
LC_ALL=C awk -v q=\' '
BEGIN{
for (i=1; i<ARGC; i++) {
gsub(q, q "\\" q q, ARGV[i])
printf "%s ", q ARGV[i] q
}
print ""
}' "$@"
}
shquote "${cmd[@]}" | ssh user@host sh
पर्यावरण चर का उपयोग करना
अब, यदि आपको क्लाइंट से दूरस्थ कमांड के स्टड पर कुछ डेटा फीड करने की आवश्यकता है, तो उपरोक्त समाधान काम नहीं करेगा।
कुछ ssh
सर्वर परिनियोजन हालांकि क्लाइंट से सर्वर पर मनमाने ढंग से पर्यावरण चर के पारित होने की अनुमति देते हैं। उदाहरण के लिए, डेबियन आधारित सिस्टम पर कई ओपनशूट परिनियोजन ऐसे चर को पार करने की अनुमति देते हैं जिनके नाम से शुरू होता है LC_
।
LC_CODE
उदाहरण के लिए, आपके पास ऊपर के रूप में shquoted sh
कोड वाले एक उदाहरण के लिए एक चर हो सकता है और sh -c 'eval "$LC_CODE"'
दूरस्थ क्लाइंट पर उस चर को फिर से पास करने के लिए कहा जा सकता है (फिर से, यह एक कमांड-लाइन है जिसकी व्याख्या हर शेल में समान है):
LC_CODE=$(shquote "${cmd[@]}") ssh -o SendEnv=LC_CODE user@host '
sh -c '\''eval "$LC_CODE"'\'
सभी शेल परिवारों के लिए संगत कमांड लाइन का निर्माण
यदि उपरोक्त में से कोई भी विकल्प स्वीकार्य नहीं है (क्योंकि आपको स्टडिन और sshd की आवश्यकता है, किसी भी चर को स्वीकार नहीं करता है, या क्योंकि आपको एक सामान्य समाधान की आवश्यकता है), तो आपको दूरस्थ होस्ट के लिए एक कमांड लाइन तैयार करनी होगी जो सभी के साथ संगत हो समर्थित गोले।
यह विशेष रूप से मुश्किल है क्योंकि उन सभी गोले (बॉर्न, csh, आरसी, तों, मछली) का अपना अलग सिंटैक्स है, और विशेष रूप से अलग-अलग उद्धरण तंत्र में और उनमें से कुछ की सीमाएं हैं जो चारों ओर काम करना मुश्किल है।
यहाँ एक समाधान है जो मैं लेकर आया हूँ, मैं इसका और वर्णन करता हूँ:
#! /usr/bin/perl
my $arg, @ssh, $preamble =
q{printf '%.0s' "'\";set x=\! b=\\\\;setenv n "\
";set q=\';printf %.0s "\""'"';q='''';n=``()echo;x=!;b='\'
printf '%.0s' '\'';set b \\\\;set x !;set -x n \n;set q \'
printf '%.0s' '\'' #'"\"'";export n;x=!;b=\\\\;IFS=.;set `echo;echo \.`;n=$1 IFS= q=\'
};
@ssh = ('ssh');
while ($arg = shift @ARGV and $arg ne '--') {
push @ssh, $arg;
}
if (@ARGV) {
for (@ARGV) {
s/'/'\$q\$b\$q\$q'/g;
s/\n/'\$q'\$n'\$q'/g;
s/!/'\$x'/g;
s/\\/'\$b'/g;
$_ = "\$q'$_'\$q";
}
push @ssh, "${preamble}exec sh -c 'IFS=;exec '" . join "' '", @ARGV;
}
exec @ssh;
कि perl
चारों ओर एक आवरण लिपि है ssh
। मैं इसे बुलाता हूं sexec
। आप इसे कहते हैं:
sexec [ssh-options] user@host -- cmd and its args
आपके उदाहरण में:
sexec user@host -- "${cmd[@]}"
और आवरण cmd and its args
एक कमांड लाइन में बदल जाता है, जो सभी शेल cmd
को अपने आर्ग्स (उनकी सामग्री के बावजूद) के साथ कॉल करने के रूप में व्याख्या करता है ।
सीमाएं:
- प्रस्तावना और जिस तरह से कमांड का हवाला दिया जाता है मतलब दूरस्थ कमांड लाइन काफी बड़ा होता है जिसका मतलब है कि कमांड लाइन के अधिकतम आकार पर सीमा जल्द ही पहुंच जाएगी।
- मैंने केवल इसके साथ परीक्षण किया है: बॉर्न शेल (हिरलूम टूलकेस्ट से), डैश, बैश, ज़श, mksh, lashh, यश, ksh93, rc, es, akanga, csh, tshsh, मछली जैसा हाल ही में डेबियन सिस्टम और / पर पाया गया। बिन / श, / usr / bin / ksh, / bin / csh और / usr / xpg4 / bin / sh Solaris 10 पर।
- यदि
yash
दूरस्थ लॉगिन शेल है, तो आप एक कमांड पास नहीं कर सकते जिसके तर्कों में अमान्य वर्ण हैं, लेकिन यह एक सीमा है yash
जिसमें आप किसी भी तरह से काम नहीं कर सकते।
- Ssh पर आह्वान करने पर कुछ गोले जैसे csh या bash कुछ स्टार्टअप फाइलें पढ़ते हैं। हम मानते हैं कि उन लोगों ने व्यवहार को नाटकीय रूप से नहीं बदला ताकि प्रस्तावना अभी भी काम करे।
- बगल में
sh
, यह भी मानता है कि रिमोट सिस्टम के पास printf
कमांड है।
यह समझने के लिए कि यह कैसे काम करता है, आपको यह जानना होगा कि अलग-अलग गोले में कैसे काम करता है:
- बॉर्न:
'...'
इसमें कोई विशेष चरित्र के साथ मजबूत उद्धरण हैं । "..."
कमजोर उद्धरण हैं, जहां "
बैकस्लैश से बचा जा सकता है।
csh
। बॉर्न के रूप में भी सिवाय इसके कि "
अंदर नहीं बचा जा सकता है "..."
। साथ ही एक बैकलाइन के साथ उपसर्ग में एक नया वर्ण दर्ज करना होगा। और !
सिंगल कोट्स के अंदर भी समस्याएं पैदा करता है।
rc
। केवल उद्धरण '...'
(मजबूत) हैं। एकल उद्धरण के भीतर एक एकल उद्धरण ''
(जैसे '...''...'
) दर्ज किया गया है । डबल उद्धरण या बैकस्लैश विशेष नहीं हैं।
es
। आरसी को उसी बाहरी उद्धरण के अलावा, बैकस्लैश एकल उद्धरण से बच सकते हैं।
fish
: बॉर्न के समान ही कि बैकस्लैश '
अंदर से बच जाता है '...'
।
उन सभी विरोधाभासों के साथ, यह देखना आसान है कि कोई मज़बूती से कमांड लाइन तर्क नहीं दे सकता है ताकि यह सभी गोले के साथ काम करे।
के रूप में एकल उद्धरण का उपयोग:
'foo' 'bar'
सभी में काम करता है लेकिन:
'echo' 'It'\''s'
में काम नहीं करेगा rc
।
'echo' 'foo
bar'
में काम नहीं करेगा csh
।
'echo' 'foo\'
में काम नहीं करेगा fish
।
लेकिन हम अपने आसपास के लोगों की समस्याओं से ज्यादातर काम करने में सक्षम है, तो हम, चर में उन समस्याग्रस्त पात्रों स्टोर करने के लिए प्रबंधन में बैकस्लैश की तरह होना चाहिए $b
, में एकल उद्धरण $q
में, न्यू लाइन $n
(और !
में $x
एक खोल स्वतंत्र रास्ते में csh इतिहास के विस्तार के लिए)।
'echo' 'It'$q's'
'echo' 'foo'$b
सभी गोले में काम करेगा। हालांकि यह अभी भी newline के लिए काम नहीं करेगा csh
। यदि $n
नईलाइन शामिल है csh
, तो, आपको $n:q
इसे किसी नई पंक्ति में विस्तारित करने के लिए लिखना होगा और यह अन्य गोले के लिए काम नहीं करेगा। इसलिए, हम यहाँ क्या कर रहे हैं sh
और कॉल कर रहे हैं और sh
उन का विस्तार किया है $n
। इसका मतलब यह भी है कि उद्धरण के दो स्तर करने के लिए, एक दूरस्थ लॉगिन शेल के लिए, और एक के लिएsh
।
$preamble
कि कोड में trickiest हिस्सा है। यह (जब यह दूसरों के लिए बाहर टिप्पणी की है) सब गोले में विभिन्न विभिन्न हवाले से नियमों के उपयोग के गोले का केवल एक से व्याख्या कोड के कुछ वर्गों के लिए सिर्फ उन को परिभाषित करने, जिनमें से प्रत्येक में आता है $b
, $q
, $n
,$x
अपने-अपने खोल के लिए चर।
यहाँ शेल कोड है जो host
आपके उदाहरण के लिए दूरस्थ उपयोगकर्ता के लॉगिन शेल द्वारा व्याख्या किया जाएगा :
printf '%.0s' "'\";set x=\! b=\\;setenv n "\
";set q=\';printf %.0s "\""'"';q='''';n=``()echo;x=!;b='\'
printf '%.0s' '\'';set b \\;set x !;set -x n \n;set q \'
printf '%.0s' '\'' #'"\"'";export n;x=!;b=\\;IFS=.;set `echo;echo \.`;n=$1 IFS= q=\'
exec sh -c 'IFS=;exec '$q'printf'$q' '$q'<%s>'$b'n'$q' '$q'arg with $and spaces'$q' '$q''$q' '$q'even'$q'$n'$q'* * *'$q'$n'$q'newlines'$q' '$q'and '$q$b$q$q'single quotes'$q$b$q$q''$q' '$q''$x''$x''$q
जब कोई समर्थित गोले द्वारा व्याख्या की जाती है तो वह कोड उसी कमांड को चलाता है।
cmd
तर्क था कि/bin/sh -c
हम सभी मामलों में 99% मामलों में एक पॉज़िक्स शेल के साथ समाप्त हो जाएंगे, तो क्या हम नहीं करेंगे? बेशक विशेष पात्रों से बचना इस तरह से थोड़ा अधिक दर्दनाक है, लेकिन क्या यह प्रारंभिक समस्या को हल करेगा?