Yerel bash betiğini uzak makinelerde ssh ile nasıl çalıştırabilirim?


51

Uzak makinelere herhangi bir şey yüklemeye gerek kalmadan konfigürasyonu bir merkezi makineden birkaç uzak makineye itmenin bir yolunu arıyorum.

Amaç, benzeri araçlarla bulacağınız gibi bir şey yapmak cfengine, ancak aracı olmayan bir dizi makinede yapmaktır. Bu aslında cfagentmevcut bir dizi uzak makineye kurulum için iyi bir teknik olabilir .



1
Asıl sorular, SO'daki yinelemenin 55: P
MoJo

Yanıtlar:


55

Bir betiği geçebilir ve onu boruya ekleyerek ve bir kabuk çalıştırarak geçici olarak yürütmesini sağlayabilirsiniz.

Örneğin

echo "ls -l; echo 'Hello World'" | ssh me@myserver /bin/bash

Doğal olarak, "ls -l; echo 'Hello World'"parça yerel makinedeki bir dosyada saklanan bash betiği ile değiştirilebilir.

Örneğin

cat script.sh | ssh me@myserver /bin/bash

Şerefe!


2
Bunu uzak sistemde sudo olarak çalışmasını nasıl sağlayabilirim.eg Uzak sunucuya giriş yapmış olsaydım, bunu genellikle sudo -u testuser script.sh olarak çalıştırırdım
14:53

Ya çağırdığım komut dosyası kullanıcı etkileşimlerini içeriyorsa ???
Abhimanyu Srivastava

20

Bunu yapmanın birkaç yolu var.

1:

ssh user@remote_server 'bash -s' < localfile

2:

cat localfile  | ssh user@remote_server

3:

ssh user@remote_server "$(< localfile)"

sayı 3 benim tercih ettiğim yoldur, etkileşimli komutlara izin verir, örneğin su -S service nginx restart

(# 1, kullandığınızda şifre sorusu için komut dosyasının geri kalanını girdi olarak kullanır su -S.)


4
Uzak bilgisayarda çalışan yerel komut dosyasını çalıştırmayla ilgili olarak - Uzak makineye değişken olarak değişken göndermenin bir yolu var mı? yani betiğin yanı sıra, uzak makineye argüman olarak bir değişken (birden fazla satır içeren) göndermek istiyorum. Betik daha sonra değişkeni kullanmayı amaçlamaktadır.

13

Bu amaç için python's Fabric'i tavsiye ederim:

#!/usr/bin/python
# ~/fabfile.py

from fabric_api import *

env.hosts = ['host1', 'host2']
def deploy_script():
    put('your_script.sh', 'your_script.sh', mode=0755)
    sudo('./your_script.sh')

# from shell
$ fab deploy_script

Başlamak için yukarıdakileri kullanabilmelisiniz. Gerisini yapmak için Fabric'in mükemmel belgelerine bakın . Ek olarak, betiğinizi tamamen Kumaşın içine yazmak tamamen mümkündür - kopyalamaya gerek yoktur, ancak betiği tüm makinelerde değiştirmek için yalnızca yerel kopyayı düzenlemeniz ve yeniden konuşlandırmanız gerekir. Ayrıca, API'nin temel kullanımından biraz daha fazlasıyla, şu anda üzerinde çalıştığı ana bilgisayarı ve / veya diğer değişkenleri temel alarak komut dosyasını değiştirebilirsiniz. Bu bir tür pitonik Beklenti.


Bunun soruyu tam olarak cevapladığını sanmıyorum, ancak fikri beğeniyorum ve Fabric'i kullanışlı bir araç olarak görebiliyordum.
23em'de

1
@ tremoloqui Fabric ssh'nin etrafındaki bir python sargısıdır - hedef makinelere hiçbir şey yüklenmemeli, betiğin kaydedilmesini önleyin. Bir dizi Kumaş komutu olarak yeniden yazılmışsa ( runve kullanarak sudo) ki gerekli değildir.
Izkata

5

Bu tam olarak Ansible'ın kullandığı şey. Aracı yok, sadece adında bir metin dosyası oluşturmanız gerekiyor:

/etc/ansible/hosts

gibi görünen bir içerikle:

[webhosts]
web[1-8]

Bu, "web1, web2 ... web8" makinelerinin "webhosts" grubunda olduğunu belirtir. Sonra gibi şeyler yapabilirsiniz:

ansible webhosts -m service -a "name=apache2 state=restarted" --sudo

Apache2 hizmetini sudo kullanarak tüm makinelerinizde yeniden başlatmak

Aşağıdaki gibi anında komutları yapabilirsiniz:

ansible webhosts -m shell -a "df -h"

veya uzak makinede yerel bir komut dosyasını çalıştırabilirsiniz:

ansible webhosts -m script -a "./script.sh"

veya sunucularınızın buna uygun olmasını ve konuşlandırılmasını istediğiniz tam bir konfigürasyona sahip bir oynatma kitabı oluşturabilir (ayrıntılar için belgelere bakın):

ansible-playbook webplaybook.yml

Temel olarak, birden çok sunucuda komut çalıştırmak için bir komut satırı aracı olarak kullanmaya başlayabilir ve kullanımını uygun gördüğünüz şekilde eksiksiz bir yapılandırma aracına genişletebilirsiniz.


3
Bir sonraki çocuk kadar çok severim, ama bir senaryo hakkında sorular soruyorsa, o zaman ansible gerçekten güzel bir script modülüne sahiptir :ansible webhosts -m script script.sh
ptman

1
Diğer tüm cevaplar bir bash betiği içerir, ancak onun için özel olarak istediği şey bu değildir. Sadece uzak makinelere yapılandırma iterek dedi. Ama script modülünden iyi söz :)
seumasmac

Lütfen bu cevabı oyla! Bunu yapmanın yolu bu!
civcivler

@ptman Sadece, soruda bir senaryodan bahsetmediği halde, başlıkta yazdığını fark ettim! Üzgünüm. Güncelledim.
seumasmac

3

Bu cevapta açıklandığı gibi, heredoc kullanabilirsiniz :

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

Heredoc ile dikkatli olmalısın, çünkü sadece metin yolluyor, ama cevabı gerçekten beklemiyor. Bu, komutlarınızın yürütülmesini beklemeyeceği anlamına gelir.


1

Buradaki cevap ( https://stackoverflow.com/a/2732991/4752883 ) plinkveya kullanarak bir uzak linux makinesinde bir komut dosyası çalıştırmayı deniyorsanız harika çalışıyor ssh. Komut dosyasında birden fazla satır varsa çalışacaktır linux.

** Ancak, yerel bulunan bir toplu komut dosyasını çalıştırmak çalışıyorsanız linux/windowsmakine ve uzak bir makinedir Windowsve bu kullanarak birden hatlarından oluşmaktadır **

plink root@MachineB -m local_script.bat

işe yaramayacak.

Sadece betiğin ilk satırı çalıştırılacak. Bu muhtemelen bir sınırlamasıdır plink.

1. Çözüm:

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

Orijinal toplu komut dosyanız aşağıdaki gibidir:

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

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

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

Bu değişiklikten sonra, betiği @ JasonR.Coombs tarafından belirtildiği şekilde çalıştırabilirsiniz: https://stackoverflow.com/a/2732991/4752883

2. Çözüm:

Toplu betiğiniz göreceli olarak karmaşıksa, @Martin https://stackoverflow.com/a/32196999/4752883 tarafından belirtildiği gibi, aşağıdaki gibi plink komutunu içeren 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

0

Neden önce sadece betiği kopyalamıyor, sonra çalıştırmıyorsunuz?

scp your_script.sh the_server:
ssh the_server "chmod +x your_script.sh; ./your_script.sh"

Elbette, dünyaca yazılabilir bir yere yüklememeye dikkat etmelisiniz, bu yüzden çalıştırmadan önce başka hiç kimse onunla oynamamış olabilir (muhtemelen root olarak).


1
Senaryoyu yüklemek istemememin nedeni yönetilmesi ve bahsettiğin risklere sahip olması gerekmiyor. Ayrıca, bana göre yükleme, işleme ve (isteğe bağlı olarak) silme işleminin çok adımlı işleminden daha basit görünüyor.
tremoloqui

0

İçinde her komut zaten bir bakıma senaryoyu yeniden edilir bağımsız değişken olarak komut geçirilir ssh ve bir ana makine adı / ip veya bu tür listesinde öneki (eğer şifresiz / ssh-agent anahtar kimlik doğrulama kurmak olduğu varsayıldığında). Uzak komutlardan hata / dönüş kodlarını doğru şekilde iletmek için bazı çalışmalar gerekebilir ....


0

Senaryo çok büyük değilse ve bash veya ksh kullanıyorsanız ...

ssh vm24 -t bash -c "$(printf "%q" "$(< shell-test.sh )")"

Hem stdin hem de stdout düzgün çalışır, ancak script argüman boyutuyla sınırlıdır (genellikle yaklaşık 100k). Betikteki argümanlar, satırın sonunda, muhtemelen fazladan bir "-" argümanını izleyerek işe yarayabilir. Bir pty tahsis etmek için "-t" isteğe bağlıdır.

Dikkat: Bu, bash tamamlanmasını karıştırır, sekmeye basmayın.

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.