सवाल एसएसएच पर सुडो का उपयोग करके मैं मनमाने ढंग से जटिल कमांड कैसे चला सकता हूं?


मेरे पास एक सिस्टम है जिसे मैं केवल अपने उपयोगकर्ता नाम (myuser) के अंतर्गत लॉग इन कर सकता हूं, लेकिन मुझे कमांड को अन्य उपयोगकर्ता (स्क्रिप्टसर) के रूप में चलाने की आवश्यकता है। अब तक, मुझे आवश्यक आदेशों को चलाने के लिए निम्नलिखित के साथ आया है:

ssh -tq myuser@hostname "sudo -u scriptuser bash -c \"ls -al\""

हालांकि, जब मैं एक और जटिल कमांड चलाने की कोशिश करता हूं, जैसे कि [[ -d "/tmp/Some directory" ]] && rm -rf "/tmp/Some directory" मैं जल्दी उद्धरण के साथ परेशानी में मिलता है। मुझे यकीन नहीं है कि मैं इस उदाहरण जटिल कमांड को कैसे पास कर सकता हूं bash -c, कब \" जो आदेश मैं गुजर रहा हूं उसकी सीमाओं को पहले से ही सीमित करता है (और इसलिए मुझे नहीं पता कि कैसे / tmp / कुछ निर्देशिका को उद्धृत करना है, जिसमें रिक्त स्थान शामिल हैं।

क्या कोई सामान्य समाधान है जो मुझे किसी भी आदेश को पारित करने की इजाजत देता है चाहे कोई उद्धरण कितना जटिल / पागल हो, या क्या यह किसी प्रकार की सीमा तक पहुंच गई है? क्या अन्य संभव और शायद अधिक पठनीय समाधान हैं?


76
2017-09-02 09:21


मूल


एक स्क्रिप्ट को $ रिमोट पर कॉपी करें और फिर इसे निष्पादित करें। - Iain
यह काम करेगा, लेकिन मुझे एक समाधान मिलता है जो पीछे कोई स्क्रिप्ट फाइल नहीं छोड़ता है (अगर कुछ विफल हो जाता है आदि) थोड़ा क्लीनर होगा। - VoY
प्रत्येक रन के अंत में स्क्रिप्ट आरएम स्वयं है - thanasisk
कपड़े का उपयोग करने पर विचार करें fabfile.org। यदि आपको दूरस्थ रूप से बहुत कुछ करना है तो आपको जीवन को और अधिक आसान बना सकता है। - Nils Toedtmann
यदि आपके पास उत्तरदायी स्थापित है तो यह आदेश आपके उपयोग के लिए दस्तावेज़ दिखाता है: ansible-doc script - bbaassssiiee


जवाब:


एक चाल जिसे मैं कभी-कभी उपयोग करता हूं, कमांड को एन्कोड करने के लिए बेस 64 का उपयोग करना है, और इसे अन्य साइट पर बैश करने के लिए पाइप करना है:

MYCOMMAND=$(base64 -w0 script.sh)
ssh user@remotehost "echo $MYCOMMAND | base64 -d | sudo bash"

यह एक सुरक्षित स्ट्रिंग के अंदर किसी भी अल्पविराम, बैकस्लैश, उद्धरण और चर के साथ स्क्रिप्ट को एन्कोड करेगा, और इसे दूसरे सर्वर पर भेज देगा। (-w0 लाइन रैपिंग को अक्षम करने के लिए आवश्यक है, जो डिफ़ॉल्ट रूप से कॉलम 76 पर होता है)। दूसरी तरफ, $(base64 -d) स्क्रिप्ट को डीकोड करेगा और इसे निष्पादित करने के लिए इसे बाश करने के लिए फ़ीड करेगा।

मुझे इसके साथ कोई समस्या नहीं मिली, इससे कोई फर्क नहीं पड़ता कि स्क्रिप्ट कितनी जटिल थी। बचने में समस्या हल करती है, क्योंकि आपको कुछ भी बचने की ज़रूरत नहीं है। यह रिमोट होस्ट पर एक फ़ाइल नहीं बनाता है, और आप आसानी से जटिल जटिल स्क्रिप्ट चला सकते हैं।


138
2017-09-02 13:10



या और भी: ssh user@remotehost "echo `base64 -w0 script.sh` | base64 -d | sudo bash" - Niklas B.
यह ध्यान देने योग्य है कि ज्यादातर मामलों में आप तेजी से स्थानांतरण समय के लिए बेस 64 के लिए lzop या gzip को प्रतिस्थापित कर सकते हैं। हालांकि, किनारे के मामले हो सकते हैं। YMMV। - CodeGnome
अच्छा नोट, लेकिन अगर यह एक स्क्रिप्ट है, तो मुझे उम्मीद है कि किसी भी स्थानांतरण को कुछ केबी से अधिक नहीं होने की उम्मीद है। - ThoriumBR
यहाँ भी गूंज का बेकार उपयोग है। base64 script | ssh remotehost 'base64 -d | sudo bash' पर्याप्त होगा :) - hobbs
आज परीक्षण किया और पूरी तरह से काम किया। धन्यवाद दोस्तों - Soham Chakraborty


देखें -tt विकल्प? को पढ़िए ssh(1) मैनुअल।

ssh -tt root@host << EOF
sudo some # sudo shouldn't ask for a password, otherwise, this fails. 
lines
of
code 
but be careful with \$variables
and \$(other) \`stuff\`
exit # <- Important. 
EOF

एक चीज जो मैं अक्सर करता हूं वह विम का उपयोग करती है और इसका उपयोग करती है :!cat % | ssh -tt somemachine छल।


32
2017-09-02 13:01



बेशक :!cat % | (command) के रूप में किया जा सकता है :w !(command) या :!(command) < %। - Scott
हाँ। मेरी लाइन एक है बिल्ली दुर्व्यवहार - moebius_eye


मुझे लगता है कि सबसे आसान समाधान @ thanasisk की टिप्पणी में संशोधन में निहित है।

एक स्क्रिप्ट बनाएं scp यह मशीन पर, फिर इसे चलाएं।

स्क्रिप्ट है rm शुरुआत में खुद ही। खोल ने फ़ाइल खोली है, इसलिए इसे लोड किया गया है, और फिर समस्याओं के बिना हटाया जा सकता है।

इस आदेश में चीजें करके (rm सबसे पहले, दूसरी चीजें दूसरी) यह किसी भी समय विफल होने पर भी हटा दी जाएगी।


9
2017-09-02 11:26





आप इसका उपयोग कर सकते हैं %q प्रारूप के साथ विनिर्देशक printf आपके लिए भागने वाले चर की देखभाल करने के लिए:

cmd="ls -al"
printf -v cmd_str '%q' "$cmd"
ssh user@host "bash -c $cmd_str"

printf -v एक चर के लिए आउटपुट लिखता है (इस मामले में, $cmd_str)। मुझे लगता है कि यह करने का यह सबसे आसान तरीका है। किसी भी फाइल को स्थानांतरित करने या कमांड स्ट्रिंग को एन्कोड करने की आवश्यकता नहीं है (जितना मुझे चाल पसंद है)।

यहां एक और जटिल उदाहरण दिखाया गया है कि यह स्क्वायर ब्रैकेट्स और एम्परसैंड जैसी चीजों के लिए भी काम करता है:

$ ssh user@host "ls -l test"
-rw-r--r-- 1 tom users 0 Sep  4 21:18 test
$ cmd="[[ -f test ]] && echo 'this really works'"
$ printf -v cmd_str '%q' "$cmd"
$ ssh user@host "bash -c $cmd_str"
this really works

मैंने इसका परीक्षण नहीं किया है sudo लेकिन यह उतना आसान होना चाहिए जितना:

ssh user@host "sudo -u scriptuser bash -c $cmd_str"

यदि आप चाहते हैं, तो आप एक कदम छोड़ सकते हैं और मध्यवर्ती चर बनाने से बच सकते हैं:

$ ssh user@host "bash -c $(printf '%q' "$cmd")"
this really works

या यहां तक ​​कि पूरी तरह से एक चर बनाने से बचें:

ssh user@host "bash -c $(printf '%q' "[[ -f test ]] && echo 'this works as well'")"

7
2017-09-04 20:10



यह एक शानदार समाधान है। मुझे वास्तव में इसी तरह की स्थिति के लिए पहले printf का उपयोग करना पड़ा था, लेकिन मैं हमेशा इसके बारे में भूल जाता हूं। इसे पोस्ट करने के लिए धन्यवाद :-) - Jon L.


बैश में इस तरह कुछ निष्पादित करने के लिए "सही" (वाक्य रचनात्मक) तरीका यहां दिया गया है:

ssh user@server "$( cat <<'EOT'
echo "Variables like '${HOSTNAME}' and commands like $( uname -a )"
echo "will be interpolated on the server, thanks to the single quotes"
echo "around 'EOT' above.
EOT
)"

ssh user@server "$( cat <<EOT
echo "If you want '${HOSTNAME}' and $( uname -a ) to be interpolated"
echo "on the client instead, omit the the single quotes around EOT."
EOT
)"

यह कैसे काम करता है इसकी पूरी तरह से व्याख्या के लिए, कृपया देखें https://stackoverflow.com/a/21761956/111948


6
2018-05-28 17:48





क्या आप जानते हैं कि आप इसका उपयोग कर सकते हैं sudo आपको एक खोल देने के लिए जहां आप चयनित उपयोगकर्ता के रूप में आदेश चला सकते हैं?

-i, --login

लॉगिन उपयोगकर्ता के रूप में लक्षित उपयोगकर्ता की पासवर्ड डेटाबेस प्रविष्टि द्वारा निर्दिष्ट खोल चलाएं। इसका मतलब है कि लॉगिन-विशिष्ट संसाधन फ़ाइलें जैसे कि                    .profile या .login खोल द्वारा पढ़ा जाएगा। यदि कोई आदेश निर्दिष्ट किया गया है, तो इसे खोल के-सी विकल्प के माध्यम से निष्पादन के लिए खोल में भेज दिया जाता है। यदि नही                    आदेश निर्दिष्ट है, एक इंटरैक्टिव खोल निष्पादित किया जाता है। sudo खोल चलाने से पहले उस उपयोगकर्ता की होम निर्देशिका में बदलने का प्रयास करता है। द कॉम-                    मंडल एक ऐसे वातावरण के साथ चलाया जाता है जो उपयोगकर्ता को लॉग इन पर प्राप्त होता है। सुडौर्स में कमांड पर्यावरण अनुभाग (5) मैनुअल डॉकू-                    ments कैसे -i विकल्प पर्यावरण को प्रभावित करता है जिसमें सुडौर्स नीति उपयोग में आने पर कमांड चलाया जाता है।


4
2017-09-03 09:22



यह मेरे लिए स्पष्ट समाधान की तरह लगता है। > सूडो-ए-ब्रायन - code_monk
रिमोट एक्सेस के मामले में "ssh -t" के साथ संयुक्त होने पर यह सबसे अच्छा काम करता है। जो प्रश्न में शामिल है, लेकिन "मैं इस / पूरे / पेज को पढ़ नहीं सकता" लोगों के लिए दोहराना भालू। :) - dannysauer


आप अपनी स्थानीय मशीन पर और फिर स्क्रिप्ट को परिभाषित कर सकते हैं cat और इसे दूरस्थ मशीन पर पाइप करें:

user@host:~/temp> echo "echo 'Test'" > fileForSsh.txt
user@host:~/temp> cat fileForSsh.txt | ssh localhost

Pseudo-terminal will not be allocated because stdin is not a terminal.
stty: standard input: Invalid argument
Test

3
2017-09-02 09:39



यूयूओसी आप <का उपयोग कर सकते हैं - Iain
क्या आप शामिल करने के लिए उदाहरण संशोधित कर सकते हैं sudo -u scriptuser? क्या हेड्रोक उपयोग करने योग्य होगा क्योंकि मुझे स्क्रिप्ट में चर होने की आवश्यकता है, मैं मशीन पर पाइप करूँगा? - VoY
मै प्रयास कर रहा था: echo "sudo `cat fileForSsh.txt`" | ssh ... लेकिन मैं मिल रहा है sudo: sorry, you must have a tty to run sudo। - jas_raj
हालांकि यह प्रश्न अगर आप प्राप्त कर सकते हैं तो मदद कर सकते हैं /etc/sudoers फ़ाइल बदल दी - jas_raj
यह मेरे लिए काम करता है: ssh -tq user@host "sudo bash -s" < test.sh - AVee


सरल और आसान।

एसएसएच उपयोगकर्ता @ servidor "bash -s" <script.sh


1
2017-09-03 20:15





यदि आप पर्याप्त आधुनिक बैश खोल का उपयोग करते हैं, तो आप अपने आदेशों को फ़ंक्शन में डाल सकते हैं और उस फ़ंक्शन को स्ट्रिंग के रूप में प्रिंट कर सकते हैं export -p -f function_name। उस स्ट्रिंग के परिणाम में मनमानी कमांड हो सकते हैं जिन्हें रूट के रूप में चलाने की आवश्यकता नहीं है।

पाइप का उपयोग कर एक उदाहरण यूनिक्स.एसई पर मेरा जवाब:

#!/bin/bash
remote_main() {
   local dest="$HOME/destination"

   tar xzv -C "$dest"
   chgrp -R www-data "$dest"
   # Ensure that newly written files have the 'www-data' group too
   find "$dest" -type d -exec chmod g+s {} \;
}
tar cz files/ | ssh user@host "$(declare -pf remote_main); remote_main"

एक उदाहरण जो पुनर्प्राप्त करता है लॉग इन उपयोगकर्ता के लिए फ़ाइल सहेजता है और एक प्रोग्राम को रूट बनाता है:

remote_main() {
    wget https://example.com/screenrc -O ~/.screenrc
    sudo apt-get update && sudo apt-get install screen
}
ssh user@host "$(declare -pf remote_main); remote_main"

यदि आप पूरे कमांड का उपयोग कर चलाना चाहते हैं sudo, आप इसका उपयोग कर सकते हैं:

remote_main() {
    wget https://example.com/screenrc -O ~user/.screenrc
    apt-get update && apt-get install screen
}
ssh user@host "$(declare -pf remote_main);
    sudo sh -c \"\$(declare -pf remote_main); remote_cmd\""
# Alternatively, if you don't need stdin and do not want to log the command:
ssh user@host "$(declare -pf remote_main);
    (declare -pf remote_main; echo remote_cmd) | sudo sh"

0
2017-09-04 09:59





यहां मेरा (वास्तव में परीक्षण नहीं किया गया) क्रैपी समाधान है:

#!/usr/bin/env ruby
# shell-escape: Escape each argument.
ARGV.each do|a|
  print " '#{a.gsub("'","\'\\\\'\'")}' "
end

आप नहीं कर सकते

ssh -tq myuser@hostname "$(shell-escape sudo -u scriptuser bash -c "$(shell-escape ls -al)")"

अगला कदम एक बनाना है betterssh लिपि जो पहले से ही यह करती है:

betterssh -tq myuser@hostname sudo -u scriptuser bash -c "$(shell-escape ls -al)"

0
2017-09-06 08:19