Получение SSH для выполнения команды в фоновом режиме на целевой машине


304

Это дополнительный вопрос к Как вы используете ssh в сценарии оболочки? вопрос. Если я хочу выполнить команду на удаленной машине, которая работает в фоновом режиме на этой машине, как мне получить команду ssh для возврата? Когда я пытаюсь просто включить амперсанд (&) в конце команды, он просто зависает. Точная форма команды выглядит следующим образом:

ssh user@target "cd /some/directory; program-to-execute &"

Любые идеи? Следует отметить, что при входе на целевой компьютер всегда появляется текстовый баннер, и у меня настроены ключи SSH , поэтому пароль не требуется.

Ответы:


315

У меня была эта проблема в программе, которую я написал год назад - оказывается, ответ довольно сложный. Вам нужно будет использовать nohup, а также перенаправление вывода, как объяснено в википедии artcle на nohup , скопированном здесь для вашего удобства.

Nohuping фоновые задания, например, полезны при входе через SSH, поскольку фоновые задания могут привести к зависанию оболочки при выходе из-за состояния гонки [2]. Эта проблема также может быть преодолена путем перенаправления всех трех потоков ввода-вывода:

nohup myprogram > foo.out 2> foo.err < /dev/null &

1
Эти файлы создаются в текущем каталоге. Таким образом, ограничение - это количество свободного места на разделе. Конечно, вы также можете перенаправить на /dev/null.
Фрэнк Кастерс

2
Любые идеи о фоновом процессе после того, как он закончил, спрашивая подсказки? (как gpg --decrypt, который закончил спрашивать пароль)
isaaclw

Попытка запустить работника resque в фоновом режиме с помощью nohup, но это не сработало .. :(
Infant Dev

1
Не могли бы вы объяснить, что это < /dev/nullзначит? Спасибо.
Цянь Чен,

1
Также из статьи в Википедии о nohup: «Также обратите внимание, что закрывающий сеанс SSH не всегда отправляет сигнал HUP зависимым процессам. Среди прочего, это зависит от того, был ли выделен псевдотерминал или нет». Так что, хотя nohup не всегда нужен, вам лучше работать с ним, чем без него.
Джекс

254

Это был самый чистый способ сделать это для меня:

ssh -n -f user@host "sh -c 'cd /whereever; nohup ./whatever > /dev/null 2>&1 &'"

После этого запускается только команда на удаленном компьютере.


7
-nне нужно, как -fследует-n
блиссини

6
ssh -fоставляет процесс SSH подключенным, просто фоновым. Решения / dev / null позволяют ssh быстро отключаться, что может быть предпочтительнее.
Бени Чернявский-Паскин

Это решение также работает для отправки команд через ssh на NAS-сервер Syonology
Stefan F

Мне нужно, чтобы результаты «ls -l» отображались на моем пульте, эта команда не делает этого.
Сиддхарт

@Siddharth Затем перенаправьте на некоторый именованный файл, а не на / dev / null.
sherrellbc

29

Перенаправить FD

Вывод должен быть перенаправлен с помощью &>/dev/nullкоторого перенаправляет как stderr, так и stdout в / dev / null и является синонимом >/dev/null 2>/dev/nullили >/dev/null 2>&1.

круглые скобки

Лучший способ - это использовать sh -c '( ( command ) & )'там, где есть команда.

ssh askapache 'sh -c "( ( nohup chown -R ask:ask /www/askapache.com &>/dev/null ) & )"'

Nohup Shell

Вы также можете использовать nohup напрямую для запуска оболочки:

ssh askapache 'nohup sh -c "( ( chown -R ask:ask /www/askapache.com &>/dev/null ) & )"'

Хороший запуск

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

ssh askapache 'nice -n 19 sh -c "( ( nohup chown -R ask:ask /www/askapache.com &>/dev/null ) & )"'

8
Я знаю, что это очень старый ваш ответ, но не могли бы вы добавить несколько комментариев о том, почему путь в скобках является лучшим способом, что (если таковые имеются) nohupделает добавление различий , и почему и когда вы будете использовать nice? Я думаю, что это многое добавит к этому ответу.
Доктор К

Может быть, частично ответить на этот вопрос: с nohup вам не нужно добавлять команду & к команде для запуска.
Cadoiz

21

Если вы не можете / не можете держать соединение открытым, вы можете использовать экран , если у вас есть права на его установку.

user@localhost $ screen -t remote-command
user@localhost $ ssh user@target # now inside of a screen session
user@remotehost $ cd /some/directory; program-to-execute &

Чтобы отсоединить сеанс экрана: ctrl-a d

Чтобы перечислить сеансы экрана:

screen -ls

Чтобы присоединить сеанс:

screen -d -r remote-command

Обратите внимание, что экран также может создавать несколько оболочек в каждом сеансе. Подобного эффекта можно добиться с помощью tmux .

user@localhost $ tmux
user@localhost $ ssh user@target # now inside of a tmux session
user@remotehost $ cd /some/directory; program-to-execute &

Чтобы отключить сеанс tmux: ctrl-b d

Чтобы перечислить сеансы экрана:

tmux list-sessions

Чтобы присоединить сеанс:

tmux attach <session number>

Управляющий ключ tmux по умолчанию, ' ctrl-b', несколько сложен в использовании, но есть несколько примеров конфигураций tmux, которые поставляются с tmux, которые вы можете попробовать.


3
как можно использовать screenдля этого?
Quamis

18

Я просто хотел показать рабочий пример, который вы можете вырезать и вставить:

ssh REMOTE "sh -c \"(nohup sleep 30; touch nohup-exit) > /dev/null &\""

Очень полезно. Спасибо.
Майкл Мартинес

8

Самый быстрый и простой способ - использовать команду at:

ssh user @ target "сейчас -f /home/foo.sh"


2
Это было бы отличным общим решением, если бы через некоторое время atпринимались аргументы командной строки, а не только из файла.
Тайлер Коллиер

3
Вы можете смоделировать файл с помощью <<< как в: ssh user @ target "сейчас -f <<< 'my_comnads'"
Нико

6

Я думаю, вам придется объединить пару ответов, чтобы получить то, что вы хотите. Если вы используете nohup в сочетании с точкой с запятой и заключаете все это в кавычки, то вы получите:

ssh user@target "cd /some/directory; nohup myprogram > foo.out 2> foo.err < /dev/null"

который, кажется, работает для меня. С nohup вам не нужно добавлять & к команде для запуска. Кроме того, если вам не нужно читать какие-либо выходные данные команды, вы можете использовать

ssh user@target "cd /some/directory; nohup myprogram > /dev/null 2>&1"

перенаправить весь вывод в / dev / null.


5

Это сработало для меня, возможно, раз:

ssh -x remoteServer "cd yourRemoteDir; ./yourRemoteScript.sh </dev/null >/dev/null 2>&1 & " 

2

Вы можете сделать это так ...

sudo /home/script.sh -opt1 > /tmp/script.out &

Отлично, работает с сессией PuTTY SSH. Я могу выйти, и сценарий продолжается на машине. Спасибо.
Сатрия

1

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

Например:

# simple_script.sh (located on remote server)

#!/bin/bash

cat /var/log/messages | grep <some value> | awk -F " " '{print $8}'

И тогда я просто запускаю эту команду на исходном компьютере:

ssh user@ip "/path/to/simple_script.sh"

0

Я пытался сделать то же самое, но с добавленной сложностью, что я пытался сделать это из Java. Таким образом, на одном компьютере с Java я пытался запустить скрипт на другом компьютере в фоновом режиме (с nohup).

Вот что сработало из командной строки: (вам может не понадобиться ключ -i, если вам не нужен ssh для хоста)

ssh -i keyFile user@host bash -c "\"nohup ./script arg1 arg2 > output.txt 2>&1 &\""

Обратите внимание, что в моей командной строке есть один аргумент после «-c», который находится в кавычках. Но для того, чтобы он работал на другом конце, ему все еще нужны кавычки, поэтому мне пришлось поместить в него экранированные кавычки.

С Java, вот что сработало:

ProcessBuilder b = new ProcessBuilder("ssh", "-i", "keyFile", "bash", "-c",
 "\"nohup ./script arg1 arg2 > output.txt 2>&1 &\"");
Process process = b.start();
// then read from process.getInputStream() and close it.

Потребовалось немного проб и ошибок, чтобы это заработало, но, похоже, сейчас это работает хорошо.


0

Мне показалось довольно удобным иметь удаленный сеанс tmux с использованием следующего tmux new -d <shell cmd>синтаксиса:

ssh someone@elsewhere 'tmux new -d sleep 600'

Это запустит новый сеанс на elsewhereхосте, а команда ssh на локальном компьютере почти мгновенно вернется в оболочку. Затем вы можете SSH к удаленному хосту иtmux attach к этому сеансу. Обратите внимание, что в локальной tmux нет ничего, кроме удаленной!

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

ssh someone@elsewhere 'tmux new -d "~/myscript.sh; bash"'

0
YOUR-COMMAND &> YOUR-LOG.log &    

Это должно запустить команду и назначить идентификатор процесса, который вы можете просто привязать -f YOUR-LOG.log, чтобы увидеть результаты, записанные в него, по мере их появления. Вы можете выйти из системы в любое время, и процесс продолжится


0

Вы можете сделать это без nohup:

ssh user@host 'myprogram >out.log 2>err.log &'

-2

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

while read pass port user ip; do
sshpass -p$pass ssh -p $port $user@$ip <<ENDSSH1
    COMMAND 1
    .
    .
    .
    COMMAND n
ENDSSH1
done <<____HERE
    PASS    PORT    USER    IP
      .      .       .       .
      .      .       .       .
      .      .       .       .
    PASS    PORT    USER    IP    
____HERE

-3

Сначала выполните эту процедуру:

Войдите в систему как пользователь a и сгенерируйте пару ключей аутентификации. Не вводите парольную фразу:

a@A:~> ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/a/.ssh/id_rsa): 
Created directory '/home/a/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/a/.ssh/id_rsa.
Your public key has been saved in /home/a/.ssh/id_rsa.pub.
The key fingerprint is:
3e:4f:05:79:3a:9f:96:7c:3b:ad:e9:58:37:bc:37:e4 a@A

Теперь используйте ssh для создания каталога ~ / .ssh от имени пользователя b на B. (Каталог может уже существовать, что нормально):

a@A:~> ssh b@B mkdir -p .ssh
b@B's password: 

Наконец, добавьте новый открытый ключ a в b @ B: .ssh / authorized_keys и введите пароль b в последний раз:

a@A:~> cat .ssh/id_rsa.pub | ssh b@B 'cat >> .ssh/authorized_keys'
b@B's password: 

Отныне вы можете войти в B как b из A как без пароля:

a@A:~> ssh b@B

тогда это будет работать без ввода пароля

ssh b @ B "cd / some / directory; программа для выполнения &"


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