Какой самый простой способ использовать ssh и запускать несколько команд в Bash?

218

У меня уже настроен агент ssh, и я могу запускать команды на внешнем сервере в Bash script, делая такие вещи, как:

ssh blah_server "ls; pwd;"

Теперь, что я действительно хотел бы сделать, это запустить много длинных команд на внешнем сервере. Закрытие всех этих элементов между кавычками было бы довольно уродливым, и я бы предпочел бы избегать ssh'ing несколько раз, чтобы этого избежать.

Итак, есть ли способ сделать это за один раз, заключенный в круглые скобки или что-то еще? Я ищу что-то вроде:

ssh blah_server (
   ls some_folder;
   ./someaction.sh;
   pwd;
)

В принципе, я буду доволен любым решением, если оно будет чистым.

Изменить

Чтобы уточнить, я говорю о том, что это часть более крупного Bash script. Другим людям, возможно, придется иметь дело с script вниз по линии, поэтому я хочу сохранить его в чистоте. Я не хочу иметь Bash script с одной строкой, которая выглядит так:

ssh blah_server "ls some_folder; ./someaction.sh 'some params'; pwd; ./some_other_action 'other params';"

потому что это чрезвычайно уродливо и трудно читать.

  • 1
    Хм, а как насчет того, чтобы поместить все это в скрипт на сервере и просто вызвать его одним ssh вызовом?
  • 0
    @Nikolai, если команды зависят от клиентской стороны, их можно записать в сценарий оболочки, затем выполнить scp , ssh и выполнить. Это будет самый чистый путь, я думаю.
Показать ещё 4 комментария
Теги:
ssh

12 ответов

291
Лучший ответ

Как насчет Bash Здесь Документ:

  ssh otherhost < < EOF ls some_folder;. /someaction.sh 'некоторые параметры' PWD. /some _other_action 'другие параметры'
EOF
Код>

Чтобы избежать проблем, упомянутых в комментариях к @Globalz, вы можете (в зависимости от того, что вы делаете на удаленном сайте) уйти с заменой первой строки

  ssh otherhost/bin/bash < < EOF
Код>

Обратите внимание, что вы можете сделать замену переменных в документе Here, но вам, возможно, придется решать проблемы с цитированием. Например, если вы укажете "предельную строку" (т.е. EOF в приведенном выше примере), то вы не сможете делать замены переменных. Но без цитирования предельной строки заменяются переменные. Например, если вы определили $NAME выше в своем сценарии оболочки, вы можете сделать

  ssh otherhost/bin/bash < < EOF
touch "/tmp/${NAME}" 
EOF
Код>

и он создаст файл в целевом otherhost с именем того, что вы назначили $NAME. Другие правила о цитировании оболочки script также применимы, но слишком сложны для перехода сюда.

  • 6
    Это выглядит именно то, что я хочу! Как это работает? Может быть, у вас есть ссылка на страницу, которая объясняет это?
  • 9
    +1 Просто думал, что сам - вот одно место, чтобы прочитать об этом: tldp.org/LDP/abs/html/here-docs.html
Показать ещё 20 комментариев
91

Измените свой script локально, а затем передайте его в ssh, например.

cat commands-to-execute-remotely.sh | ssh blah_server

где commands-to-execute-remotely.sh выглядит как ваш список выше:

ls some_folder
./someaction.sh
pwd;
  • 6
    Это имеет большое преимущество в том, что вы точно знаете , что выполняется удаленным скриптом - никаких проблем с цитированием. Если вам нужны динамические команды, вы можете использовать сценарий оболочки с подоболочкой, который все еще находится в ssh, т.е. ( echo $mycmd $myvar ; ...) | ssh myhost - как и в случае с cat, вы точно знаете, что входит в поток команд ssh. И, конечно, подобная оболочка в сценарии может быть многострочной для удобства чтения - см. Linuxjournal.com/content/bash-sub-shells
  • 5
    Можете ли вы сделать это с аргументами в commands-to-execute-remotely.sh ?
Показать ещё 3 комментария
32

Я вижу два пути:

Сначала вы создаете контрольный сокет следующим образом:

 ssh -oControlMaster=yes -oControlPath=~/.ssh/ssh-%r-%h-%p <yourip>

и запустите свои команды

 ssh -oControlMaster=no -oControlPath=~/.ssh/ssh-%r-%h-%p <yourip> -t <yourcommand>

Таким образом вы можете написать команду ssh без фактического повторного подключения к серверу.

Вторым было бы динамическое создание script, scp и его запуск.

27

Чтобы соответствовать вашему образцу кода, вы можете обернуть свои команды внутри одного или двух qoutes. Например

ssh blah_server "
  ls
  pwd
"
  • 0
    Мне нравится этот формат, но, к сожалению, он бесполезен для хранения стандартных данных в переменной.
  • 1
    Сигнус, что ты имеешь в виду под "хранением стандартных данных в переменной"?
Показать ещё 2 комментария
15

Это также можно сделать следующим образом. Поместите свои команды в script, назовите его command-inc.sh

#!/bin/bash
ls some_folder
./someaction.sh
pwd

Сохраните файл

Теперь запустите его на удаленном сервере.

ssh user@remote 'bash -s' < /path/to/commands-inc.sh

Мне никогда не приходило в голову.

  • 0
    Подобно тому, что я думал первоначально! Но зачем нужен bash -s ?
  • 0
    Кроме того, #!/bin/bash действительно используется?
Показать ещё 4 комментария
7

SSH и выполните несколько команд в Bash.

Разделяйте команды с точкой с запятой внутри строки, переданной в эхо, все переданные в команду ssh. Например:

echo "df -k;uname -a" | ssh 192.168.79.134

Pseudo-terminal will not be allocated because stdin is not a terminal.
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sda2       18274628 2546476  14799848  15% /
tmpfs             183620      72    183548   1% /dev/shm
/dev/sda1         297485   39074    243051  14% /boot
Linux newserv 2.6.32-431.el6.x86_64 #1 SMP Sun Nov 10 22:19:54 EST 2013 x86_64 x86_64 x86_64 GNU/Linux
  • 0
    Арнаб, в будущем опишите, пожалуйста, вкратце, что делает ваш код. Затем поговорите о том, как это работает, затем вставьте код. Затем поместите код в блок кода, чтобы его было легко прочитать.
  • 0
    Исходя из вопроса, вы предложили именно то , чего ОП хочет избежать: «Я не хочу иметь скрипт bash с одной строкой, которая выглядит как ...»
7

Поместите все команды на script, и его можно запустить как

ssh <remote-user>@<remote-host> "bash -s" <./remote-commands.sh
  • 0
    Несколько странно, но это хорошо работает. И аргументы могут быть переданы в сценарий (до или после перенаправления). например, 'ssh <удаленный пользователь> @ <удаленный хост> "bash -s" arg1 <./ remote-commands.sh arg2' например, 'ssh <удаленный пользователь> @ <удаленный хост> "bash -s" - - -arg1 <./ remote-commands.sh arg2 '
  • 0
    У меня был похожий вопрос с другим ответом выше, но какова цель включения bash -s ?
Показать ещё 3 комментария
3

Для тех, кто наткнулся на меня, как на меня, я добился успеха в том, что вы избегали точки с запятой и новой строки:

Первый шаг: точка с запятой. Таким образом, мы не нарушаем команду ssh:

ssh <host> echo test\;ls
                    ^ backslash!

Перечислил удаленный хост/домашний каталог (зарегистрированный как root), тогда как

ssh <host> echo test;ls
                    ^ NO backslash

отображает текущий рабочий каталог.

Следующий шаг: разрыв строки:

                      v another backslash!
ssh <host> echo test\;\
ls

Это снова отобразило удаленный рабочий каталог - улучшенное форматирование:

ssh <host>\
  echo test\;\
  ls

Если действительно лучше, чем здесь, документ или цитаты вокруг ломаных строк - ну, не мне решать...

(Используя bash, Ubuntu 14.04 LTS.)

3

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

#!/bin/bash
ssh <my_user>@<my_host> "bash -s" << EOF
    # here you just type all your commmands, as you can see, i.e.
    touch /tmp/test1;
    touch /tmp/test2;
    touch /tmp/test3;
EOF
  • 0
    Часть "$ (which bash) -s" дает вам местоположение bash на локальной машине, а не на удаленной машине. Я думаю, что вы хотите вместо этого использовать $ (which bash) -s (одинарные кавычки для подавления подстановки локальных параметров).
  • 1
    Пол Томблин предоставил ответ на документ Bash Here Document 6 лет назад. Какую ценность добавляет этот ответ?
Показать ещё 1 комментарий
3

Мысль:

Оберните свои длинные команды в bash script, scp на конечный сервер, выполните его с помощью ssh и добавьте команду delete-self в конце script.

2

Самый простой способ настроить вашу систему на использование одиночных сеансов ssh по умолчанию с мультиплексированием.

Это можно сделать, создав папку для сокетов:

mkdir ~/.ssh/controlmasters

И затем добавив следующее в вашу конфигурацию .ssh:

Host *
    ControlMaster auto
    ControlPath ~/.ssh/controlmasters/%r@%h:%p.socket
    ControlMaster auto
    ControlPersist 10m

Теперь вам не нужно изменять какой-либо код. Это позволяет многократные вызовы ssh и scp без создания нескольких сеансов, что полезно, когда требуется дополнительное взаимодействие между локальными и удаленными компьютерами.

Спасибо @terminus answer, http://www.cyberciti.biz/faq/linux-unix-osx-bsd-ssh-multiplexing-to-speed-up-ssh-connections/ и https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Multiplexing.

0

Опубликованные ответы с использованием многострочных строк и нескольких сценариев bash не работали для меня.

  • Длинные многострочные строки трудно поддерживать.
  • Отдельные bash скрипты не поддерживают локальные переменные.

Вот функциональный способ ssh и запускать несколько команд, сохраняя локальный контекст.

LOCAL_VARIABLE=test

run_remote() {
    echo "$LOCAL_VARIABLE"
    ls some_folder; 
    ./someaction.sh 'some params'
    ./some_other_action 'other params'
}

ssh otherhost "$(set); run_remote"
  • 2
    Вы думаете об этом, как будто единственная причина, по которой кто-то захочет это сделать, - это то, что они сидят за командной строкой. Есть и другие общие причины для этого вопроса, такие как выполнение команд в распределенных средах с помощью таких инструментов, как rundeck, jenkins и т. Д.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню