Mengapa perintah `cd` tidak berfungsi melalui SSH?


41

Saya mencoba untuk membuat cadangan beberapa file melalui SSH tetapi alih-alih taryang saya inginkan saya mendapat folder rumah saya. Saya melakukan beberapa pengujian lebih lanjut dan intinya adalah:

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

Yang mengejutkan saya daftar file dalam /roottidak /boot. Tetapi jika saya menjalankan seluruh /bin/shperintah dari terminal dengan benar cddan mencetak /bootfile.

Apa yang sedang terjadi disini?


1
Kecuali jika ini adalah contoh, mengapa Anda tidak menggunakan ssh root@server /bin/sh -c "ls -l /boot"?
demure

Lucu sekali kau bertanya. Saya mencoba melakukan itu sebelum berkomentar dan masih tidak mendapatkan daftar direktori.
unxnut

2
@demure karena saya benar-benar ingin tar, dan tar / boot akan menyertakan jalur boot di hasilnya, yang saya tidak mau
Ambroz Bizjak

Jawaban:


35

ssh tidak membiarkan Anda menentukan perintah secara tepat, seperti yang telah Anda lakukan, sebagai serangkaian argumen untuk diteruskan ke execvp pada host jarak jauh. Sebaliknya itu menggabungkan semua argumen menjadi string dan menjalankannya melalui shell jarak jauh. Ini menonjol sebagai cacat desain utama dalam ssh menurut saya ... itu adalah alat unix berperilaku baik dalam banyak hal, tetapi ketika tiba saatnya untuk menentukan perintah yang ia pilih untuk menggunakan string monolitik tunggal alih-alih argv, seperti itu dirancang untuk MSDOS atau apalah!

Karena ssh akan meneruskan perintah Anda sebagai string tunggal sh -c, Anda tidak perlu menyediakan sendiri sh -c. Ketika Anda melakukannya, hasilnya adalah

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

dengan kutipan aslinya hilang. Jadi perintah yang dipisahkan oleh &&adalah:

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

Yang pertama menjalankan shell dengan teks perintah "cd" dan $0= "boot". Perintah "cd" berhasil diselesaikan, $0itu tidak relevan, dan yang /bin/sh -cmenunjukkan keberhasilan, maka yang ls -lterjadi.


2
Meskipun saya setuju bahwa disayangkan bahwa sshberperilaku seperti itu, jika tidak, itu harus dipanggil sexec, bukan ssh. sshadalah versi aman rsh(yang berperilaku sama dalam hal itu) dan rlogin( rshdipanggil rloginsaat tidak melewati baris perintah). Sangat disayangkan bahwa itu tidak diterapkan rexecjuga.
Stéphane Chazelas

@StephaneChazelas apakah pernah ada perintah rexec? Itu hanya fungsi C library sejauh yang saya tahu. Poin bagusnya, tentang rsh. Menjadi pengganti drop-in untuk rsh adalah kunci untuk adopsi cepat di hari-hari awal ssh, ketika semua orang memiliki banyak skrip yang sudah menggunakan rsh.

Saya pasti menggunakannya di masa lalu. Melihat sekarang, itu pasti ada di HPUX karena tidak banyak Unix lain sepertinya memilikinya, saya harus mengakui meskipun saya mendapat kesan itu lebih luas.
Stéphane Chazelas

Terima kasih. Ini sangat membantu, khususnya. karena saya tunneling dengan ssh. Saya harus melakukan ssh -t machine1 'ssh -t machine2 "echo \" 1 && 2 \ ""' untuk mendapatkan '1 && 2' sebagai output. Itu menewaskan beberapa jam.
ghayes

Jika Anda benar-benar ingin memberikan perintah, misalnya dari "$ @", Anda dapat menggunakan ini: "`printf "%q " "$@"`"dengan bash's printfuntuk mengutip string atau string dengan shell escapes.
Sam Watkins

36

Ini masalah mengutip. Ssh sudah menjalankan perintah yang Anda berikan dalam sebuah shell. Ketika Anda melewati beberapa parameter, mereka digabungkan dengan spasi di antaranya untuk membangun string. Jadi perintah jarak jauh yang Anda jalankan dari jarak jauh adalah /bin/sh -c cd /boot && ls -l(tidak ada tanda kutip, karena tanda kutip di perintah Anda ditafsirkan oleh shell lokal).

/bin/sh -c cd /bootmenjalankan /bin/shdan memberi tahu untuk menjalankan perintah cddan juga untuk mengatur $0ke/boot . Setelah ini selesai, shell induk (yang diluncurkan oleh sshd) berjalan ls -l.

Dalam kasus Anda, hapus saja sh -cyang benar-benar tidak berguna kecuali shell jarak jauh Anda (seperti yang ditunjukkan dalam /etc/passwdatau basis data kata sandi lainnya) tidak memahami perintah ini.

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

Jika Anda perlu memanggil shell yang berbeda, Anda harus mengutip perintah remote untuk melindunginya dari ekspansi oleh shell remote yang dipanggil oleh sshd. Misalnya, jika shell login Anda putus-putus dan Anda ingin menjalankan perintah bash:

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

8

Saya pikir ini lebih berkaitan dengan bagaimana opsi semakin diurai oleh shell. Misalnya, ini berfungsi:

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

Ini memiliki masalah yang sama dengan perintah Anda:

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

Jika Anda mengaktifkan -vperalihan ke sshAnda dapat melihat apa yang terjadi:

Perintah 1:

debug1: Mengirim perintah: / bin / sh -c "cd / boot && ls -l"

Perintah 2:

debug1: Mengirim perintah: / bin / sh -c cd / boot && ls -l

Biasanya ketika mengirim perintah melalui sshAnda harus memberi perhatian khusus pada kutipan dan bungkus kutipan dalam tanda kutip karena berbagai lapisan menghapusnya. Juga jangan repot mengirim/bin/sh .

Anda dapat melakukan hal yang sangat berguna setelah Anda memahami kutipan sshseperti berikut ini. Ini akan menjalankan perintah pada server jauh tetapi mengumpulkan hasil dalam file secara lokal pada sistem tempat Anda menjalankan sshperintah:

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

atau ini, tempat Anda menempatkan direktori pada server jarak jauh dan membuatnya di sistem lokal:

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

Referensi


4

Biasanya Anda tidak harus menentukan shell apa yang akan digunakan. Ini bekerja:

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

Tetapi jika shell default Anda bermasalah, maka pastikan Anda mengutip seluruh perintah, termasuk doa shell. Salah satu dari karya-karya berikut

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

Perhatikan bahwa sementara cd /boot && pwdbekerja di semua cangkang keluarga besar (Bourne, csh, rc), /bin/sh -c "cd /boot && pwd"tidak akan berfungsi jika cangkang jarak jauh adalah dari rckeluarga "yang tidak spesial.
Stéphane Chazelas
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.