Cd` komutu neden SSH ile çalışmıyor?


39

Bazı dosyaları SSH ile yedeklemeye çalışıyordum, ancak taristediklerim yerine ev klasörümü aldım. Bazı testler yaptım ve bu aşağı kaynıyor:

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

Benim sürpriz listeleri dosyalarına hangi /rootdeğil /boot. Fakat eğer /bin/shkomutun tamamını bir uçbirimden çalıştırırsam düzgün bir şekilde cds ve /bootdosyaları yazdırır .

Burada neler oluyor?


1
Bu bir örnek olmadığı sürece neden kullanmıyorsun ssh root@server /bin/sh -c "ls -l /boot"?
çekingen

İstediğin komik. Yorum yapmadan önce bunu yapmaya çalıştım ve yine de dizin listelemedi.
unxnut

2
@demure çünkü gerçekten tar istedim ve tar / boot, istemiyorum ki sonuçta boot yolunu da içerecek
Ambroz Bizjak

Yanıtlar:


32

ssh, komutun tam olarak, sizin yaptığınız gibi, uzak ana bilgisayarda çalıştırılacak bir dizi argüman olarak belirtilmesine izin vermez. Bunun yerine, tüm argümanları bir dizgede birleştirir ve uzak bir kabuk üzerinde çalıştırır. Bu bence ssh’da büyük bir tasarım hatası olarak göze çarpıyor ... birçok yönden iyi davranışlı bir unix aracı, ancak bir komut belirtme zamanı geldiğinde, bir argv yerine tek bir monolitik dize kullanmayı seçti. MSDOS ya da başka bir şey için tasarlandı!

Ssh emrinizi tek bir dizge olarak geçireceğinden, kendi dilinizi vermenize sh -cgerek yoktur sh -c. Bunu yaptığınızda, sonuç

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

orijinal alıntı ile kaybedildi. Yani ile ayrılmış komutlar &&:

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

Bunlardan ilki, "cd" ve $0= komut metnini içeren bir kabuk çalıştırır "boot". "Cd" komutu başarılı bir şekilde tamamlanır $0, konuyla ilgisizdir ve /bin/sh -cbaşarıyı gösterir, sonra ls -lolur.


2
Ben kabul ederken o talihsiz ssho olmasaydı böyle davranırlar, bu çağrılacak olurdu sexec, değil ssh. (bu konuda aynı şekilde davranan) ve ( bir komut satırını geçmediğinde çağrılan ) sshgüvenli versiyonudur . Sadece uygulamaması da talihsizlik . rshrloginrshrloginrexec
Stéphane Chazelas

@StephaneChazelas hiç bir rexec komutu oldu mu? Bildiğim kadarıyla sadece bir C kütüphane işlevi var. Rsh hakkında olsa iyi nokta. Herkesin zaten rsh kullandığı tonlarca komut dosyası bulunduğunda, ssh'nin yerine geçmesi, ssh'nin ilk günlerinde hızlı bir şekilde benimsenmesinin anahtarıydı.

Kesinlikle geçmişte kullandım. Şimdi bakıldığında, diğer pek çok Uniceside göründüğü gibi HPUX'da olmalıydı, daha yaygın olduğu izlenimi altında olsa da itiraf etmeliyim.
Stéphane Chazelas

Teşekkürler. Bu gerçekten yardımcı oldu, esp. o zamandan beri ssh ile tünel açıyorum. Çıktı olarak '1 & 2' almak için ssh -t machine1 'ssh -t machine2 "echo \" 1 && 2 \ ""' yapmak zorunda kaldım. Bu birkaç saat öldürdü.
ghayes

Bir komutu tam olarak, örneğin "$ @" den geçirmek istiyorsanız, şunu kullanabilirsiniz: "`printf "%q " "$@"`"bash printfile kabuk kaçan bir dize veya dizeler alıntı yapmak için.
Sam Watkins

35

Bu bir alıntı konusu. Ssh zaten bir kabukta geçirdiğiniz komutu çalıştırıyor. Birden çok parametre ilettiğinizde, bunlar bir dize oluşturmak için aralarında bir boşlukla birleştirilir. Böylece uzaktan çalıştırdığınız uzak komut şöyledir /bin/sh -c cd /boot && ls -l(tırnak işaretleri yoktur, çünkü komutunuzdaki tırnaklar yerel kabuk tarafından yorumlanmıştır).

/bin/sh -c cd /bootçalışır /bin/shve komutu çalıştırmak için söyler cdsete de ve $0için /boot. Bu yapıldıktan sonra ana kabuk (tarafından başlatılan sshd) çalışır ls -l.

Sizin durumunuzda, sh -cuzak kabuğunuz ( /etc/passwdya da başka bir şifre veritabanında belirtildiği gibi ) bu komutu anlamadıkça , hangisini tamamen işe yaramazsa kaldırın .

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

Farklı bir kabuk çağırmanız gerekirse, tarafından çağrılan uzak kabuğun genişlemesini önlemek için remote komutunu vermeniz gerekir sshd. Örneğin, giriş kabuğunuz kısa çizgi ise ve bir bash komutu çalıştırmak istiyorsanız:

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

8

Seçeneklerin kabuk tarafından nasıl ayrıştırılacağı ile ilgili olduğunu düşünüyorum. Örneğin, bu çalışır:

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

Bu, emrinizle aynı konuyu içeriyor:

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

-vDüğmeyi etkinleştirirseniz, sshneler olduğunu görebilirsiniz:

1. komut:

debug1: Gönderme komutu: / bin / sh -c "cd / boot && ls -l"

2. komut:

debug1: Gönderme komutu: / bin / sh -c cd / boot && ls -l

Genellikle komutları gönderirken ssh, çeşitli katmanlar bunları sıyırırken alıntılara ve tırnak içindeki tırnaklara özel önem vermeniz gerekir. Ayrıca gönderme zahmet etmeyin /bin/sh.

sshAşağıdaki gibi alıntıyı anladıktan sonra çok faydalı bir şey yapabilirsiniz . Bu, uzak sunucudaki komutu çalıştıracak ancak sonuçları yerel olarak sshkomutu çalıştırdığınız sistemdeki bir dosyada toplayacaktır :

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

ya da uzak bir sunucuda bir dizin tartıp yerel sistemde oluşturduğunuzda:

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

Referanslar


4

Genellikle hangi kabuğun kullanılacağını belirtmeniz gerekmez. Bu çalışıyor:

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

Fakat eğer varsayılan kabuğunuz problemli ise, sadece kabuk çağrısı dahil tüm emri verdiğinizden emin olun . Aşağıdaki çalışmalardan biri

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

Not ederken o cd /boot && pwdbüyük ailelerin (Bourne, csh, rc) tüm kabuklarda eserler /bin/sh -c "cd /boot && pwd"uzak kabuk arasında ise işe yaramaz rcailesinin "özel değildir.
Stéphane Chazelas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.