Bash: พรอมต์ระยะไกลแบบโต้ตอบ


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 ดังนั้นเมื่อ bash ไปอ่านจาก STDIN สคริปต์ของคุณจะได้รับ (หรือไม่มีอะไรเลยเพราะอ่านแล้วทั้งสคริปต์และไม่มีอะไรเหลือ)
Patrick

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
นั่นคือสิ่งที่ฉันกำลังมองหาขอบคุณ!
Anthony Ananich

วิธีแก้ปัญหาที่ดี แต่มีวิธีที่จะผ่านการโต้แย้งไปyour scriptในขณะที่การรักษาข้อดีของไวยากรณ์ที่คุณใช้ในคำตอบของคุณ? โดยใช้ผลเพียงในssh -t yourserver "$(<your_script --some_arg)" bash: --some_arg: command not found
sampablokuper

1
@sampablokuper: ลองssh ... $(<script) script_arg1 script_arg2 ...
Mat

@ แมทขอบคุณ WFM :) อาจเพิ่มไปยังเนื้อหาของคำตอบของคุณหรือไม่
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 เป็นการดำเนินการที่ยาวที่สุดและฉันพยายามหลีกเลี่ยง
Anthony Ananich

@AnthonyAnanich คุณสามารถบันทึกเวลาการจัดตั้งการเชื่อมต่อโดยการตั้งค่าการเชื่อมต่อปริญญาโท
Gilles 'SO- หยุดความชั่วร้าย'

@Gilles ฉันคิดว่าจะแนะนำ แต่ฉันคิดว่ามันจะไม่ทำงานกับคำแนะนำของฉัน หากการเชื่อมต่อ ssh ที่ 1 ทำหน้าที่เป็นหลักการเชื่อมต่อนั้นจะถูกปิดหลังจากที่$OUT=$(ssh root@server rpm -qa | grep "$1");ออกแล้วการเชื่อมต่อที่ 2 จะใช้เวลานานเท่าที่หนึ่ง ฉันผิดหรือเปล่า?
terdon

1
@terdon เรียกใช้บางอย่างเช่นssh -M foo.example.com sleep 99999999หรือssh -M foo.example.com read <somefifoเป็นหลักและฆ่ามันอย่างชัดเจน (ด้วยkillหรือecho done >somefifo) เมื่อคุณทำเสร็จแล้ว
Gilles 'หยุดความชั่วร้าย'

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เหมือนกับที่ OP ทำหรือไม่ คุณสามารถรวมคำอธิบายไว้ในคำตอบของคุณแทนที่จะเชื่อมโยงกับมันได้หรือไม่?
terdon

โอ๊ะฉันขอโทษที่ลืมเพิ่มบางสิ่งที่สำคัญ ฉันยังคัดลอกสคริปต์ไปยังรีโมทเพื่อหลีกเลี่ยงการเปลี่ยนเส้นทางในเครื่อง ฉันจะต่อท้ายคำตอบเพื่อให้ชัดเจน
X Tian

1
หากคุณคัดลอกสคริปต์ไปยังรีโมทปัญหาจะหายไป ปัญหาของ OP คือเขาพยายามให้อินพุตแบบโต้ตอบกับสคริปต์โลคัลรันจากระยะไกล แน่นอนมันจะทำงานของคุณคัดลอกไป OP ต้องการเรียกใช้สคริปต์นี้เมื่อเชื่อมต่อกับเซิร์ฟเวอร์ระยะไกลน่าจะเป็นเซิร์ฟเวอร์ระยะไกลจำนวนมาก ฉันสงสัยว่าการคัดลอกมันเป็นจริงเว้นแต่คุณจะทำให้เป็นอัตโนมัติ
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) ซึ่งอาร์กิวเมนต์สามารถเป็นไฟล์อินพุตในตัวเครื่องได้เช่นกัน ดูที่นี่


น่าสนใจ แต่วิธีการและ / หรือนี้จะดีกว่าคำตอบของ Mat ?
สกอตต์

1
คำตอบของ Matเป็นผ่านครั้งแรกที่ดี (ซึ่งฉันมักจะใช้) แต่ก็ไม่สามารถจัดการสคริปต์ของเนื้อหาโดยพลการเช่น"ตัวละครที่จะต้องหลบหนี และมันถูก จำกัด ไว้ที่สคริปต์ BASH โซลูชันของฉันเป็นกรณีทั่วไปสำหรับเนื้อหาสคริปต์ของภาษาสคริปต์ที่ติดตั้งใด ๆ เพิ่มเติมในsshxฉันยังแสดงให้เห็นถึงไฟล์อาร์กิวเมนต์ต่อเนื่องซึ่งเป็นที่สวย
SourceSimian

(1) คุณสามารถโพสต์ MCVE ของสคริปต์ที่คำตอบของ Mat ล้มเหลว (และคุณใช้งานได้)? (2) ดูมีอะไรผิดปกติกับ“ echo $ (สิ่งของ)” หรือ“ echo `stuff`”? echo "$(cat my_script | base64)" | base64 --decodeรูปลักษณ์ ของคุณเทียบเท่า (-ish) ถึงcat my_script | base64 | base64 --decodeซึ่งมีลักษณะเหมือนไม่มีตัวเลือก
สกอตต์

สวัสดี @Scott (1): 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ที่นี่ (a) ทำงานอย่างมีประสิทธิภาพ: bash -c $'#!/bin/bash\necho "ARG1=$1, USER=$USER, END" foo'หรือสิ่งที่คล้ายกัน โปรดสังเกตว่า arg ไม่ทำงาน อยู่ที่ไหน (ข) bash <(echo IyEvY...5EIgo= | base64 --decode) fooคือการทำงาน: (2) ฉันใช้ base64 เป็นการเข้ารหัสการขนส่ง
SourceSimian
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.