เหตุใดคำสั่ง `cd` จึงไม่ทำงานผ่าน SSH


39

ฉันพยายามสำรองไฟล์บางไฟล์ผ่าน SSH แต่แทนที่จะเอาไฟล์tarที่ฉันต้องการฉันมีโฟลเดอร์บ้านของฉัน ฉันทำการทดสอบเพิ่มเติมและมันก็ลดลงไปถึงสิ่งนี้:

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

ซึ่งไปยังไฟล์รายการแปลกใจของฉันในไม่ได้/root /bootแต่ถ้าฉันรัน/bin/shคำสั่งทั้งหมดจากเทอร์มินัลมันจะทำการcds และพิมพ์/bootไฟล์

เกิดอะไรขึ้นที่นี่


1
ถ้าไม่ใช่นี่เป็นตัวอย่างทำไมคุณไม่ใช้ssh root@server /bin/sh -c "ls -l /boot"?
เอียง

เป็นเรื่องตลกที่คุณถาม ฉันพยายามทำอย่างนั้นก่อนที่จะแสดงความคิดเห็นและยังไม่ได้รับรายชื่อไดเรกทอรี
unxnut

2
@dure เพราะฉันต้องการ tar จริง ๆ และ tar / boot จะรวมเส้นทางการบู๊ตในผลลัพธ์ซึ่งฉันไม่ต้องการ
Ambroz Bizjak

คำตอบ:


32

ssh ไม่อนุญาตให้คุณระบุคำสั่งอย่างแม่นยำเหมือนที่คุณทำในชุดของอาร์กิวเมนต์ที่จะถูกส่งผ่านไปยัง execvp บนโฮสต์ระยะไกล แทนที่จะเชื่อมอาร์กิวเมนต์ทั้งหมดเข้ากับสตริงและเรียกใช้ผ่านเชลล์ระยะไกล นี่เป็นข้อบกพร่องที่สำคัญในการออกแบบ 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"คำสั่ง "cd" เสร็จสมบูรณ์เรียบร้อยแล้วคำสั่ง$0ไม่เกี่ยวข้องและ/bin/sh -cบ่งชี้ความสำเร็จจากนั้นls -lเกิดขึ้น


2
ขณะที่ฉันเห็นมันเป็นโชคร้ายที่sshประพฤติเช่นนั้นถ้ามันไม่ได้ก็จะต้องได้รับการเรียกว่าไม่sexec เป็นเวอร์ชันที่ปลอดภัยของ(ซึ่งทำงานเหมือนกันในเรื่องนั้น) และ( เรียกเมื่อไม่ผ่านบรรทัดคำสั่ง) เป็นเรื่องน่าเสียดายที่มันไม่ได้ใช้งานเช่นกัน sshsshrshrloginrshrloginrexec
Stéphane Chazelas

@StephaneChazelas เคยมีคำสั่ง rexec ไหม? มันเป็นแค่ฟังก์ชั่นไลบรารี C เท่าที่ฉันรู้ จุดดีแม้ว่าประมาณ rsh การแทนที่แบบแทนที่สำหรับ rsh คือกุญแจสำคัญในการนำไปใช้อย่างรวดเร็วในวันแรก ๆ ของ ssh เมื่อทุกคนมีสคริปต์จำนวนมากที่ใช้ rsh อยู่แล้ว

ฉันเคยใช้มันมาแล้วในอดีต มองตอนนี้คงต้องอยู่ใน HPUX เพราะมี Unices อื่น ๆ ที่ดูเหมือนจะมีอยู่ฉันต้องยอมรับว่าฉันรู้สึกว่ามันแพร่หลายมากขึ้น
Stéphane Chazelas

ขอบคุณ สิ่งนี้ช่วยได้จริงๆ ตั้งแต่ฉันขุดอุโมงค์ด้วย ssh ฉันต้องทำ ssh -t machine1 'ssh -t machine2 "echo \" 1 && 2 \ ""' เพื่อรับ '1 && 2' เป็นผลลัพธ์ นั่นฆ่าไม่กี่ชั่วโมง
gayes

หากคุณต้องการส่งคำสั่งอย่างแม่นยำเช่นจาก "$ @" คุณสามารถใช้สิ่งนี้: "`printf "%q " "$@"`"กับ bash's printfเพื่ออ้างอิงสตริงหรือสตริงด้วยการยกเว้นของเชลล์
Sam Watkins

35

ไม่เป็นปัญหาข้อความ 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หากคุณจำเป็นต้องเรียกใช้เปลือกแตกต่างกันคุณจะต้องพูดคำสั่งระยะไกลเพื่อปกป้องมันจากการขยายตัวจากระยะไกลเปลือกเรียกโดย ตัวอย่างเช่นหากเปลือกเข้าสู่ระบบของคุณเป็นเส้นประและคุณต้องการเรียกใช้คำสั่ง bash:

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คุณจะเห็นสิ่งที่เกิดขึ้น:

คำสั่งที่ 1:

debug1: การส่งคำสั่ง: / bin / sh -c "cd / boot && ls -l"

คำสั่งที่ 2:

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ทำงานในเชลล์ทั้งหมดของตระกูลหลัก (Bourne, csh, rc) /bin/sh -c "cd /boot && pwd"จะไม่ทำงานหากเชลล์ระยะไกลเป็นของrcตระกูลที่"ไม่พิเศษ
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.