Uzak bir makinede kabuk komut dosyası çalıştırmak için SSH nasıl kullanılır?


1220

Uzak bir makinede bir kabuk komut dosyası (windows / Linux) çalıştırmam gerekiyor.

Hem A hem de B makinesinde SSH yapılandırdım. Betiğim, kodumun bir kısmını uzak bir makinede, B makinesinde çalıştıracak A makinesinde.

Yerel ve uzak bilgisayarlar Windows veya Unix tabanlı sistem olabilir.

Bunu plink / ssh kullanarak çalıştırmanın bir yolu var mı?


6
Aynı soru zaten serverfault'da: serverfault.com/questions/215756/… Bu yüzden bu soruyu taşımanın bir anlamı yok.
sleske

9
Sunucu Hatası ile ilgili sorunun yanıtı çok fazla değil. Belki de bu soru bunun yerini almalıdır.
Büyük McLargeHuge

5
Bu yanıtı şahsen beğendim
mikevoermans

27
Ayrıca ssh, yazılım geliştirme için temel bir araç olduğu için konuyla ilgili olmalıdır.
static_rtti

4
Kahve ve ssh soruları, SO'da aynı derecede konu dışı ilgiyi paylaşmaz. Oy verildi reopen.
Vincent Cantin

Yanıtlar:


1192

Makine A Windows kutusu ise, Plink (parçası kullanabilirsiniz PuTTY -m parametresi ile) ve uzak sunucuda yerel komut çalıştırır.

plink root@MachineB -m local_script.sh

Makine A, Unix tabanlı bir sistemse aşağıdakileri kullanabilirsiniz:

ssh root@MachineB 'bash -s' < local_script.sh

Çalıştırmak için komut dosyasını uzak sunucuya kopyalamanız gerekmez.


11
-sseçeneği kullanmanın bir avantajı var mı? bu kılavuz sayfası-s , kullanılsın veya kullanılmasın işleme seçenekleri tamamlandığında standart girdiyi işleyeceğine inanmamı sağlıyor .
11:41

79
Gereken bir komut dosyası için sudoçalıştırın ssh root@MachineB 'echo "rootpass" | sudo -Sv && bash -s' < local_script.sh.
bradley.ayers

6
@ bradley.ayers bir 'boşluk' geçmişini atlamak için (PS olması gerekir ile komutu başlatmak için hatırlıyorum HISTCONTROL=ignoreboth or ignorespaceo iş yapmak)
derenio

8
@ bradley.ayers root olarak giriş yapıyorsanız hangi durumlarda sudo'ya ihtiyacınız var?
Brian Schlenker

21
@Agostino, buna benzer parametreler ekleyebilirsiniz: ssh root@MachineB ARG1="arg1" ARG2="arg2" 'bash -s' < local_script.sh Krediler aşağıdaki @ chubbsondubs'ın cevabına tam olarak gider.
Yves Van Broekhoven

633

Bu eski bir soru ve Jason'ın cevabı iyi çalışıyor, ancak bunu eklemek istiyorum:

ssh user@host <<'ENDSSH'
#commands to run on remote host
ENDSSH

Bu, kullanıcı girişi gerektiren su ve komutlarla da kullanılabilir. ( 'kaçan heredoca dikkat edin )

Düzenleme: Bu cevap trafik bit almaya devam ettiğinden, benedoc bu harika kullanımına daha fazla bilgi eklemek istiyorum:

Bu sözdizimiyle komutları iç içe yerleştirebilirsiniz ve iç içe yerleştirmenin işe yaradığı tek yol budur (aklı başında)

ssh user@host <<'ENDSSH'
#commands to run on remote host
ssh user@host2 <<'END2'
# Another bunch of commands on another host
wall <<'ENDWALL'
Error: Out of cheese
ENDWALL
ftp ftp.secureftp-test.com <<'ENDFTP'
test
test
ls
ENDFTP
END2
ENDSSH

Aslında telnet, ftp, vb.Gibi bazı servislerle sohbet edebilirsiniz.

Düzenleme: Sadece ile içini girintileyebilirsiniz öğrendim sekmelerin kullanırsanız <<-END!

ssh user@host <<-'ENDSSH'
    #commands to run on remote host
    ssh user@host2 <<-'END2'
        # Another bunch of commands on another host
        wall <<-'ENDWALL'
            Error: Out of cheese
        ENDWALL
        ftp ftp.secureftp-test.com <<-'ENDFTP'
            test
            test
            ls
        ENDFTP
    END2
ENDSSH

(Bunun işe yarayacağını düşünüyorum)

Ayrıca bkz. Http://tldp.org/LDP/abs/html/here-docs.html


4
gibi satırlar ekleyerek biraz temporize edebilirsiniz: # $ (uyku 5)
Olivier Dulac

50
sonlandırıcı ( <<'ENDSSH') etrafındaki tek tırnak işaretleri ile dizelerin genişletilmeyeceğini, değişkenlerin değerlendirilmeyeceğini unutmayın. Ayrıca <<ENDSSHveya <<"ENDSSH"genişletme istiyorsanız da kullanabilirsiniz .
13:38

3
ExpectFTP gibi etkileşimli komutları otomatikleştirmeniz gerektiğinde kullanılabilir.
programaths

5
Bir Pseudo-terminal will not be allocated because stdin is not a terminal.mesajım olduğunu unutmayın . Bundan -t -tkaçınmak için ssh parametrelerini kullanmalısınız . Bu konuyu görmek için tıklayınız ... SO
Buzut

8
<< - 'END' sözdizimini kullanmaya çalışıyorsanız, yorumlu sonlandırma sınırlayıcınızın boşluk değil TAB kullanarak girintili olduğundan emin olun. Stackexchange'ten kopyala / yapıştır işleminin size boşluk sağlayacağını unutmayın. Bunları sekmelere değiştirin ve girinti özelliği çalışmalıdır.
fbicknel

249

Ayrıca, değişkenleri hedef ana bilgisayardan almak istiyorsanız değişkenlerden kaçmayı unutmayın.

Bu beni geçmişte yakaladı.

Örneğin:

user@host> ssh user2@host2 "echo \$HOME"

çıktılar / ev / kullanıcı2

süre

user@host> ssh user2@host2 "echo $HOME"

çıktılar / ev / kullanıcı

Başka bir örnek:

user@host> ssh user2@host2 "echo hello world | awk '{print \$1}'"

"merhaba" yı doğru yazdırır.


2
Ancak aşağıdakilere dikkat edin: ssh user2@host 'bash -s' echo $HOME /home/user2 exit
errant.info

1
Bunu for, sshoturumda çalışan döngülere eklemek için döngü değişkeninden kaçılmaması gerekir.
AlexeyDaryin

1
Birçok durumda, son örneğinizi düzeltmenin akıllı yolu ssh user2@host2 'echo hello world' | awk '{ print $1 }', Awk betiğini yerel olarak çalıştırmak olacaktır . Uzak komut büyük bir çıktı üretiyorsa, elbette hepsini yerel sunucuya kopyalamaktan kaçınmak istersiniz. Bu arada, uzak komutun etrafındaki tek tırnaklar herhangi bir kaçış ihtiyacını ortadan kaldırır.
tripleee

151

Bu, satır içi uzaktan komutları ENV değişkenlerini yerel makineden uzak ana makineye geçirme ile birleştirmek için verilen yanıtın bir uzantısıdır, böylece uzak taraftaki komut dosyalarınızı parametrelendirebilirsiniz:

ssh user@host ARG1=$ARG1 ARG2=$ARG2 'bash -s' <<'ENDSSH'
  # commands to run on remote host
  echo $ARG1 $ARG2
ENDSSH

Bunu çok okunabilir ve bakımı kolay bir komut dosyasında tutarak son derece yararlı buldum.

Neden çalışıyor? ssh aşağıdaki sözdizimini destekler:

ssh user @ host Instagram Hesabındaki Resim ve Videoları remote_command

Bash'da, aşağıdaki gibi tek bir satırda bir komut çalıştırmadan önce tanımlanacak ortam değişkenlerini belirtebiliriz:

ENV_VAR_1 = 'değer1' ENV_VAR_2 = 'değer2' bash -c 'echo $ ENV_VAR_1 $ ENV_VAR_2'

Bu, bir komutu çalıştırmadan önce değişkenleri tanımlamayı kolaylaştırır. Bu durumda yankı çalıştırdığımız komutumuzdur. Ekodan önceki her şey ortam değişkenlerini tanımlar.

Bu nedenle bu iki özelliği ve YarekT'nin cevabını birleştiriyoruz:

ssh kullanıcı @ host ARG1 = $ ARG1 ARG2 = $ ARG2 'bash -s' << 'ENDSSH' ...

Bu durumda ARG1 ve ARG2'yi yerel değerlere ayarlıyoruz. User_ host'dan sonraki her şeyi remote_command olarak gönderme. Uzak makine, ARG1 ve ARG2 komutunu yürüttüğünde, uzak sunucudaki ortam değişkenlerini tanımlayan yerel komut satırı değerlendirmesi sayesinde, yerel değerler ayarlanır, ardından bu değişkenleri kullanarak bash -s komutunu yürütür. Voila.


1
Eğer -a gibi bir argümanı iletmek istiyorsanız - kullanabilirsiniz. örneğin 'ssh user @ host - -a foo bar' bash -s '<script.sh'. Args ayrıca yönlendirme işleminden sonra da gidebilir, örneğin 'ssh user @ host' bash -s '<script.sh - -a foo bar'.
gaoithe

8
Env değişken değerlerinden herhangi biri boşluk içeriyorsa, ssh user@host "ARG1=\"$ARG1\" ARG2=\"$ARG2\"" 'bash -s' <<'ENDSSH'...
şunları

Başka bir yorumda yazdığım gibi, kullanmanın -sasıl amacı stdin'den kaynaklı komut dosyalarına argümanlar uygulayabilmektir. Yani, kullanmayacaksanız da atlayabilirsiniz. Bunu kullanırsanız, ortam değişkenlerini kullanmanız için bir neden yoktur:ssh user@host 'bash -s value1 value2' <<< 'echo "$@"'
JoL

104
<hostA_shell_prompt>$ ssh user@hostB "ls -la"

HostA kullanıcısının genel anahtarını, .ssh dizinindeki ana sayfadaki yetkili_anahtarlar dosyasına kopyalamadıysanız, sizden parola istenir. Bu, şifresiz kimlik doğrulamasına izin verir (ssh sunucusunun yapılandırmasında bir kimlik doğrulama yöntemi olarak kabul edilirse)


3
Seni oyladı. Bu geçerli bir çözümdür. Açıkçası, anahtarlar korunmalıdır, ancak aynı zamanda sunucu tarafı üzerinden bir parola gibi geçersiz kılınabilirler.
willasaywhat

8
Bunun soruyu cevapladığını sanmıyorum. Örnekte, uzak bir komutun nasıl çalıştırılacağı gösterilmektedir, ancak uzak bir makinede yerel bir komut dosyasının nasıl çalıştırılacağı gösterilmemektedir.
Jason R.Combs

Emin değilsiniz ancak script'inizi hostA üzerinde bu yöntemi kullanarak hostB üzerinde çalıştıramazsınız?
nevets1219

27

Fabric'i daha karmaşık işlemler için kullanmaya başladım . Kumaş, Python ve diğer birkaç bağımlılığı gerektirir, ancak yalnızca istemci makinede. Sunucunun yalnızca bir ssh sunucusu olması gerekir. Bu aracı, SSH'ye teslim edilen kabuk komut dosyalarından çok daha güçlü ve kurulum yapma zahmetine değer buluyorum (özellikle Python'da programlamadan hoşlanıyorsanız). Fabric, birden fazla ana bilgisayarda (veya belirli rollerin ana bilgisayarlarında) çalışan komut dosyalarını işler, idempotent işlemleri kolaylaştırmaya yardımcı olur (yapılandırma komut dosyasına satır eklemek, ancak zaten orada değilse) ve daha karmaşık mantığın (Python gibi) oluşturulmasına izin verir dil sağlayabilir).


11

Koşmayı deneyin ssh user@remote sh ./script.unx.


8
Bu yalnızca komut dosyası uzaktan kumandadaki varsayılan (home) dizindeyse çalışır. Ben soru nasıl uzaktan yerel olarak depolanan bir komut dosyası çalıştırmak olduğunu düşünüyorum.
metasim

1
ssh kullanıcı adı @ ip "chmod + x script.sh" <br/> ssh kullanıcı adı @ ip "uzak ana bilgisayarda sh dosyası yolu"
mani deepak



5

Ben bir uzak makinede (/ bin / bash üzerinde test edilmiş) bir kabuk komut dosyası çalıştırmak için bunu kullanın:

ssh deploy@host . /home/deploy/path/to/script.sh

3
ssh user@hostname ".~/.bashrc;/cd path-to-file/;.filename.sh"

ortam dosyasının (.bashrc / .bashprofile / .profile) kaynaklanması önerilir. uzak ana bilgisayarda bir şey çalıştırmadan önce hedef ve kaynak ana bilgisayar ortam değişkenleri farklı olabilir.


Bu, yerel bir komut dosyasının uzak ana bilgisayara nasıl taşınacağını açıklamaz.
kirelagin

2

temp=`ls -a` echo $temp `` bu komutta olduğu gibi bir komut yürütmek istiyorsanız hatalara neden olur.

Aşağıdaki komut bu sorunu çözecektir ssh user@host ''' temp=`ls -a` echo $temp '''


1

Buradaki cevap ( https://stackoverflow.com/a/2732991/4752883 ) plinkveya komutunu kullanarak uzak bir linux makinesinde komut dosyası çalıştırmaya çalışıyorsanız harika çalışır ssh. Komut dosyasının üzerinde birden fazla satır varsa çalışır linux.

** Ancak, yerel bir linux/windowsmakinede bulunan bir toplu komut dosyasını çalıştırmaya çalışıyorsanız ve uzak makineniz ise Windowsve ** kullanarak birden çok satırdan oluşursa

plink root@MachineB -m local_script.bat

işe yaramaz.

Komut dosyasının yalnızca ilk satırı yürütülür. Bu muhtemelenplink .

Çözüm 1:

Çok satırlı bir toplu komut dosyası çalıştırmak için (özellikle birkaç satırdan oluşan nispeten basitse):

Orijinal toplu komut dosyanız aşağıdaki gibi ise

cd C:\Users\ipython_user\Desktop 
python filename.py

"&&" ayırıcısını kullanarak local_script.batdosyanızda aşağıdaki gibi satırları birleştirebilirsiniz : https://stackoverflow.com/a/8055390/4752883 :

cd C:\Users\ipython_user\Desktop && python filename.py

: Bu değişiklikten sonra, daha sonra @ JasonR.Coombs burada sivri out gibi komut çalıştırabilirsiniz https://stackoverflow.com/a/2732991/4752883 ile:

`plink root@MachineB -m local_script.bat`

Çözüm 2:

Toplu komut dosyanız nispeten karmaşıksa, plink komutunu kapsayan ve @Martin https://stackoverflow.com/a/32196999/4752883 tarafından burada belirtildiği gibi bir toplu komut dosyası kullanmak daha iyi olabilir :

rem Open tunnel in the background
start plink.exe -ssh [username]@[hostname] -L 3307:127.0.0.1:3306 -i "[SSH
key]" -N

rem Wait a second to let Plink establish the tunnel 
timeout /t 1

rem Run the task using the tunnel
"C:\Program Files\R\R-3.2.1\bin\x64\R.exe" CMD BATCH qidash.R

rem Kill the tunnel
taskkill /im plink.exe

1

Bu bash betiği bir hedef uzak makineye ssh yapar ve uzak makinede bir komut çalıştırır, çalıştırmadan önce beklemeyi yüklemeyi unutmayın (Mac'te brew install expect)

#!/usr/bin/expect
set username "enterusenamehere"
set password "enterpasswordhere"
set hosts "enteripaddressofhosthere"
spawn ssh  $username@$hosts
expect "$username@$hosts's password:"
send -- "$password\n"
expect "$"
send -- "somecommand on target remote machine here\n"
sleep 5
expect "$"
send -- "exit\n"

1
şifreleri kullanmanız gerekiyorsa bu harika ... ancak evde izleyen herkesin yararına herhangi bir ssh komutu şifreleri değil bir çift ortak + özel anahtar kullanmalıdır ... bir kez yerinde ssh sunucunuzu tamamen kapatmak için ssh sunucunuzu güncelleyin
Scott Stensland

-1

Runoverssh kullanabilirsiniz :

sudo apt install runoverssh
runoverssh -s localscript.sh user host1 host2 host3...

-s yerel bir komut dosyasını uzaktan çalıştırır


Faydalı bayraklar:
-g tüm ana makineler için genel bir parola kullanın (tek parola istemi)
-nortak anahtar kimlik doğrulaması için yararlı olan sshpass yerine SSH kullanır


-24

İlk olarak, scp kullanarak komut dosyasını Makine B'ye kopyalayın

[user @ machineA] $ scp / path / to / script kullanıcı @ machineB: / home / user / path

Sonra betiği çalıştırın

[kullanıcı @ makineA] $ ssh kullanıcı @ makineB "/ ev / kullanıcı / yol / komut dosyası"

Komut dosyasına yürütülebilir izin verdiyseniz, bu işe yarayacaktır.


merhaba önerilen önerileri uyguladım ama bana şu hatayı veriyor [oracle @ node1 ~] $ ssh oracle @ node2: ./ home / oracle / au / fs / conn.sh ssh: node2: ./ home / oracle / au / fs / conn.sh: İsim veya hizmet bilinmiyor [oracle @ node1 ~] $

'ssh oracle @ node2: ./ home / oracle / au / fs / conn.sh'? Yanlış komut satırı, komut adının user @ host bölümünden iki nokta üst üste işaretiyle değil, boşlukla ayrılması gerekir.
bortzmeyer

5
Bunu aşağıya indiriyorum, çünkü kopyalanmadan çalıştırılamayacağının birincil iddiası yanlış.
Jason R.Combs

Jason, bunun gerçeği belirtmek yerine neden yanlış olduğunu ekledi. Yararsız'ı.
Kris

[user @ machineA] $ ssh root @ MachineB 'bash -s' </ machinea / path / to / script
Oleksii Kyslytsyn
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.