Как запустить локальный скрипт bash на удаленных машинах через ssh?


51

Я ищу способ перенести конфигурацию с одного центрального компьютера на несколько удаленных машин без необходимости устанавливать что-либо на удаленных машинах.

Цель состоит в том, чтобы сделать что-то похожее на инструменты, подобные тем cfengine, но на множестве машин, на которых не настроены агенты. На самом деле это может быть хорошей техникой настройки cfagentна множестве существующих удаленных машин.



1
Фактические вопросы имеют 23 возражения, где дубликат на SO имеет 55: P
MoJo

Ответы:


55

Вы можете передать сценарий и заставить его исполниться эфемерно, отправив его и выполнив оболочку.

например

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

Естественно, эту "ls -l; echo 'Hello World'"часть можно заменить скриптом bash, который хранится в файле на локальном компьютере.

например

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

Ура!


2
Как сделать так, чтобы это выполнялось как sudo на удаленном system.eg Если бы я вошел на удаленный сервер, я обычно запускал бы это как sudo -u testuser script.sh
Sharjeel

Что если сценарий, который я вызываю, включает взаимодействие с пользователем ???
Абхиманью Шривастава

20

Есть несколько способов сделать это.

1:

ssh user@remote_server 'bash -s' < localfile

2:

cat localfile  | ssh user@remote_server

3:

ssh user@remote_server "$(< localfile)"

номер 3 - мой предпочтительный способ, он позволяет интерактивные команды, например su -S service nginx restart

(# 1 будет использовать остальную часть скрипта в качестве ввода для вопроса о пароле, когда вы используете su -S.)


4
Что касается запуска локального сценария на удаленной машине - есть ли способ отправить переменную в качестве аргумента на удаленную машину? т.е. вместе со скриптом я хочу отправить переменную (имеющую несколько строк) в качестве аргумента на удаленную машину. Затем сценарий намеревается использовать переменную.

13

Я бы порекомендовал Python's Fabric для этой цели:

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

Вы должны быть в состоянии использовать вышеупомянутое, чтобы начать. Обратитесь к отличной документации Fabric, чтобы сделать все остальное. Как дополнение, вы можете полностью написать свой скрипт в Fabric - копирование не требуется, однако следует отметить, что для изменения скрипта на всех машинах вам нужно будет только отредактировать локальную копию и заново развернуть ее. Более того, немного больше, чем просто базовое использование API, вы можете изменить сценарий в зависимости от того, на каком хосте он в данный момент работает и / или других переменных. Это своего рода питонический Ожидание.


Я не думаю, что это точно отвечает на вопрос, но мне нравится идея, и я мог бы видеть Fabric как полезный инструмент.
тремолоки

1
@tremoloqui Fabric - это оболочка Python для ssh - на целевых машинах ничего не нужно устанавливать, кроме скрипта, который передается. Что, если переписать в виде серии команд Fabric (используя runи sudo), даже не нужно.
Изката

5

Это именно то, для чего используется Ansible. Там нет агента, вам просто нужно создать текстовый файл с именем:

/etc/ansible/hosts

с контентом, который выглядит примерно так:

[webhosts]
web[1-8]

Это будет означать, что машины "web1, web2 ... web8" находятся в группе "webhosts". Тогда вы можете делать такие вещи, как:

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

перезапустить службу apache2 на всех ваших машинах, используя sudo.

Вы можете делать на лету команды, такие как:

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

или вы можете запустить локальный скрипт на удаленной машине:

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

или вы можете создать playbook (подробности смотрите в документации) с полной конфигурацией, которой вы хотите, чтобы ваши серверы соответствовали, и развернуть ее:

ansible-playbook webplaybook.yml

По сути, вы можете начать использовать его в качестве инструмента командной строки для запуска команд на нескольких серверах и расширить его использование в полноценный инструмент настройки по своему усмотрению.


3
Мне нравится ansible так же, как и следующему парню, но если он спрашивает о скрипте, то у ansible есть действительно хороший скрипт-модуль :ansible webhosts -m script script.sh
ptman

1
Все остальные ответы включают bash-скрипт, но это не то, что он специально просил. Он просто сказал, что отправляю конфигурацию на удаленные машины. Но хорошее упоминание о модуле сценария :)
seumasmac

Пожалуйста, проголосуйте за этот ответ! Это способ сделать это!
птенцы

@ptman Я только что заметил, что, хотя он не упоминает сценарий в вопросе, он упоминает в названии! Сожалею. Я обновил.
Сеумасмак

3

Как объясняется в этом ответе, вы можете использовать heredoc :

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

Вы должны быть осторожны с heredoc, потому что он просто отправляет текст, но на самом деле не ждет ответа. Это означает, что он не будет ждать выполнения ваших команд.


1

Ответ здесь ( https://stackoverflow.com/a/2732991/4752883 ) прекрасно работает, если вы пытаетесь запустить скрипт на удаленной машине Linux с помощью plinkили ssh. Это будет работать, если скрипт имеет несколько строк linux.

** Однако, если вы пытаетесь запустить пакетный скрипт, расположенный на локальном linux/windowsкомпьютере, а ваш удаленный компьютер есть Windows, и он состоит из нескольких строк, используя **

plink root@MachineB -m local_script.bat

это не сработает.

Будет выполнена только первая строка скрипта. Это, вероятно, ограничение plink.

Решение 1:

Чтобы запустить многострочный пакетный скрипт (особенно, если он относительно простой и состоит из нескольких строк):

Если ваш оригинальный пакетный скрипт выглядит следующим образом

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

Вы можете объединить строки, используя разделитель «&&», как показано в вашем local_script.batфайле следующим образом https://stackoverflow.com/a/8055390/4752883 :

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

После этого изменения вы можете запустить скрипт, как указано здесь @ JasonR.Coombs: https://stackoverflow.com/a/2732991/4752883

Решение 2:

Если ваш пакетный сценарий относительно сложен, может быть лучше использовать пакетный сценарий, который инкапсулирует команду plink, а также следующие действия, указанные здесь @Martin https://stackoverflow.com/a/32196999/4752883 :

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

Почему бы просто не скопировать сначала сценарий, а затем запустить его?

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

Конечно, вы должны быть осторожны, чтобы не загружать его в доступное для записи место, чтобы никто другой не мог возиться с ним до того, как вы запустите его (возможно, от имени root).


1
Причина, по которой я не хочу загружать скрипт, заключается в том, что им не нужно управлять и иметь риски, о которых вы упомянули. Кроме того, мне кажется, что это проще, чем многоэтапный процесс загрузки, обработки и (необязательно) удаления.
тремолоки

0

Перепишите сценарий таким образом , что каждая команда в нем уже будет с приставкой SSH и имя хоста / IP или список таких передается в скрипт в качестве аргумента (если у вас есть ключ аутентификации SSH-агент без пароля / настройки). Может потребоваться некоторая работа для правильной передачи кодов ошибок / возврата из удаленных команд ....


0

Если скрипт не слишком большой, и вы используете bash или ksh ...

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

И stdin, и stdout работают правильно, но сценарий ограничен размером аргумента (обычно около 100 КБ). Аргументы сценария могут работать в конце строки, возможно, после дополнительного аргумента "-". «-T» для выделения pty является необязательным.

Осторожно: это смущает завершение bash, не нажимайте вкладку.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.