Como executo um script bash local em máquinas remotas via ssh?

47

Estou procurando uma maneira de empurrar a configuração de uma máquina central para várias máquinas remotas sem a necessidade de instalar nada nas máquinas remotas.

O objetivo é fazer algo como você encontraria com ferramentas como cfengine , mas em um conjunto de máquinas que não possuem agentes configurados. Isso pode realmente ser uma boa técnica para configurar cfagent em um conjunto de máquinas remotas existentes.

    
por tremoloqui 23.12.2010 / 19:41

9 respostas

52

Você pode passar um script e executá-lo efêmero, canalizando-o e executando um shell.

por exemplo,

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

Naturalmente, a parte "ls -l; echo 'Hello World'" pode ser substituída por um script bash armazenado em um arquivo na máquina local.

por exemplo,

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

Felicidades!

    
por 23.12.2010 / 19:47
18

Existem várias maneiras de fazer isso.

1:

ssh user@remote_server 'bash -s' < localfile

2:

cat localfile  | ssh user@remote_server

3:

ssh user@remote_server "$(< localfile)"

o número 3 é o meu caminho preferido, permite comandos interativos, por ex. su -S service nginx restart

(# 1 consumirá o restante do script como entrada para a pergunta de senha quando você usar su -S .)

    
por 15.05.2014 / 10:41
12

Eu recomendaria o Fabric do Python para esse propósito:

#!/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

Você deve poder usar o acima para começar. Consulte a excelente documentação da Fabric para fazer o resto. Como um adendo, é totalmente possível escrever seu script totalmente dentro do Fabric - sem copiar necessário, no entanto, deve-se notar que para alterar o script em todas as máquinas, você só precisa editar a cópia local e reimplantar. Além disso, com um pouco mais do que o uso básico da API, você pode modificar o script com base em qual host está sendo executado e / ou outras variáveis. É uma espécie de expectativa pythonic.

    
por 23.12.2010 / 21:33
5

É exatamente para isso que o Ansible é usado. Não há agente, você só precisa criar um arquivo de texto chamado:

/etc/ansible/hosts

com conteúdo semelhante a:

[webhosts]
web[1-8]

Isso especificaria que as máquinas "web1, web2 ... web8" estão no grupo "webhosts". Então você pode fazer coisas como:

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

para reiniciar o serviço apache2 em todas as suas máquinas, usando o sudo.

Você pode fazer comandos imediatos como:

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

ou você pode executar um script local na máquina remota:

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

ou você pode criar um livro de exercícios (procure a documentação para obter detalhes) com uma configuração completa na qual deseja que seus servidores estejam em conformidade e implante-os com:

ansible-playbook webplaybook.yml

Basicamente, você pode começar a usá-lo como uma ferramenta de linha de comando para executar comandos em vários servidores e expandir seu uso para uma ferramenta de configuração completa, conforme desejar.

    
por 15.08.2014 / 11:35
3

Como explicado em esta resposta , você pode usar heredoc :

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

Você tem que ter cuidado com o heredoc, porque ele apenas envia um texto, mas ele realmente não espera pela resposta. Isso significa que não esperará que seus comandos sejam executados.

    
por 13.12.2012 / 15:24
1

A resposta aqui ( link ) funciona muito bem se você está tentando executar um script em um linux remoto máquina usando plink ou ssh . Ele funcionará se o script tiver várias linhas em linux .

** No entanto, se você tentando executar um script em lote localizado em uma máquina local linux/windows e sua máquina remota é Windows e consiste em várias linhas usando **

plink root@MachineB -m local_script.bat

não funciona.

Apenas a primeira linha do script será executada. Este é provavelmente um limitação de plink .

Solução 1:

Para executar um script em lotes de várias linhas (especialmente se for relativamente simples, consistindo em algumas linhas):

Se o seu script em lote original é o seguinte

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

você pode combinar as linhas usando o "& &" separador da seguinte forma em seu local_script.bat da seguinte forma link :

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

Após essa alteração, você pode executar o script como indicado aqui por @ JasonR.Coombs: link

Solução 2:

Se o seu script em lote for relativamente complicado, talvez seja melhor usar um lote script que encapsula o comando plink, bem como segue, como indicado aqui por @Martin link :

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
    
por 19.04.2018 / 23:09
0

Por que não copiar primeiro o script e depois executá-lo?

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

É claro que você deve tomar cuidado para não fazer o upload para um local gravável pelo mundo, para que ninguém mais possa mexer com isso antes de executá-lo (possivelmente como root).

    
por 23.12.2010 / 20:00
0

Reescreva o script de uma forma que cada comando nele já seja prefixado com ssh e um hostname / ip ou lista de tal seja passado para o script como um argumento (supondo que você tenha passwordless / ssh configuração de autenticação de chave de agente). Algum trabalho pode ser necessário para passar corretamente os códigos de erro / retorno dos comandos remotos ....

    
por 13.12.2012 / 15:31
0

Se o script não for muito grande e você estiver usando o bash ou o ksh ...

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

O stdin e o stdout funcionam corretamente, mas o script é limitado ao tamanho do argumento (normalmente, cerca de 100k). Argumentos para o script podem funcionar, no final da linha, possivelmente seguindo um argumento "-" extra. O "-t" para alocar um pty é opcional.

Cuidado: isso confunde a conclusão do bash, não clique em tab.

    
por 17.03.2018 / 00:32