Obtenir ssh pour exécuter une commande en arrière-plan sur la machine cible

304

Il s'agit d'une question complémentaire à Comment utilisez-vous ssh dans un script shell? question. Si je veux exécuter une commande sur la machine distante qui s'exécute en arrière-plan sur cette machine, comment puis-je obtenir la commande ssh pour revenir? Lorsque j'essaie d'inclure simplement l'esperluette (&) à la fin de la commande, elle se bloque simplement. La forme exacte de la commande ressemble à ceci:

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

Des idées? Une chose à noter est que les connexions à la machine cible produisent toujours une bannière de texte et j'ai des clés SSH configurées donc aucun mot de passe n'est requis.

dagorym
la source

Réponses:

315

J'ai eu ce problème dans un programme que j'ai écrit il y a un an - il s'avère que la réponse est plutôt compliquée. Vous devrez utiliser nohup ainsi que la redirection de sortie, comme expliqué dans l'article de wikipedia sur nohup , copié ici pour votre commodité.

Aucun travail en arrière-plan n'est utile, par exemple, lorsque vous êtes connecté via SSH, car les travaux en arrière-plan peuvent entraîner le blocage du shell à la déconnexion en raison d'une condition de concurrence critique [2]. Ce problème peut également être résolu en redirigeant les trois flux d'E / S:

nohup myprogram > foo.out 2> foo.err < /dev/null &
Jax
la source
1
Ces fichiers sont créés dans le répertoire courant. La limite est donc la quantité d'espace libre sur la partition. Bien sûr, vous pouvez également rediriger vers /dev/null.
Frank Kusters
2
Avez-vous des idées sur la mise en contexte du processus une fois qu'il a fini de demander des invites? (comme un gpg - décrypter qui a fini de demander le mot de passe)
isaaclw
Essayer de démarrer un travailleur de resque en arrière-plan à l'aide de nohup, mais cela ne fonctionne pas. :(
Infant Dev
1
Pouvez-vous expliquer ce < /dev/nullque cela signifie? Merci.
Qian Chen
1
Également de l'article de wikipedia sur nohup: "Notez également qu'une session SSH de fermeture n'envoie pas toujours un signal HUP aux processus dépendants. Entre autres, cela dépend si un pseudo-terminal a été alloué ou non." Donc, bien que strictement le nohup ne soit pas toujours nécessaire, vous êtes mieux à long terme avec que sans.
Jax
254

Cela a été la façon la plus propre de le faire pour moi: -

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

La seule chose qui s'exécute après cela est la commande réelle sur la machine distante

Russ
la source
7
-nn'est pas nécessaire comme l' -findique-n
blissini
6
ssh -flaisse le processus ssh connecté, juste en arrière-plan. Les solutions / dev / null permettent à ssh de se déconnecter rapidement, ce qui pourrait être préférable.
Beni Cherniavsky-Paskin
Cette solution fonctionne également pour l'envoi de commandes via ssh à un NAS Syonology
Stefan F
J'ai besoin que les résultats de "ls -l" s'affichent sur ma télécommande, cette commande ne le fait pas.
Siddharth
@Siddharth Ensuite, redirigez vers un fichier nommé plutôt que / dev / null.
sherrellbc
29

Rediriger les fd

La sortie doit être redirigée avec &>/dev/nulllaquelle redirige à la fois stderr et stdout vers / dev / null et est un synonyme de >/dev/null 2>/dev/nullou >/dev/null 2>&1.

Parantheses

La meilleure façon est d'utiliser sh -c '( ( command ) & )'où la commande est n'importe quoi.

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

Nohup Shell

Vous pouvez également utiliser nohup directement pour lancer le shell:

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

Nice Launch

Une autre astuce consiste à utiliser nice pour lancer la commande / shell:

ssh askapache 'nice -n 19 sh -c "( ( nohup chown -R ask:ask /www/askapache.com &>/dev/null ) & )"'
Webmaster AskApache
la source
8
Je sais que c'est une très vieille réponse de votre part, mais pourriez-vous ajouter quelques commentaires sur la raison pour laquelle la manière entre parenthèses est la meilleure, quelle différence (le cas échéant) l'ajout nohupfait, et pourquoi et quand vous l'utiliseriez nice? Je pense que cela ajouterait beaucoup à cette réponse.
Dr K
Peut-être pour répondre en partie à ceci: avec nohup, vous n'avez pas besoin d'ajouter le & à la commande à exécuter.
Cadoiz
21

Si vous ne maintenez pas / ne pouvez pas garder la connexion ouverte, vous pouvez utiliser l' écran , si vous avez les droits pour l'installer.

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 &

Pour détacher la session écran: ctrl-a d

Pour répertorier les sessions d'écran:

screen -ls

Pour rattacher une session:

screen -d -r remote-command

Notez que l'écran peut également créer plusieurs shells dans chaque session. Un effet similaire peut être obtenu avec tmux .

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

Pour détacher la session tmux: ctrl-b d

Pour répertorier les sessions d'écran:

tmux list-sessions

Pour rattacher une session:

tmux attach <session number>

La clé de contrôle tmux par défaut, ' ctrl-b', est quelque peu difficile à utiliser, mais il existe plusieurs exemples de configurations tmux livrées avec tmux que vous pouvez essayer.

hometoast
la source
3
comment utiliserait-on screencela?
Quamis
18

Je voulais juste montrer un exemple de travail que vous pouvez couper et coller:

ssh REMOTE "sh -c \"(nohup sleep 30; touch nohup-exit) > /dev/null &\""
cmcginty
la source
Très utile. Merci.
Michael Martinez
8

Le moyen le plus rapide et le plus simple consiste à utiliser la commande «at»:

ssh user @ target "at now -f /home/foo.sh"

neil
la source
2
Ce serait une excellente solution générale si les atarguments de ligne de commande étaient acceptés après l'heure et pas seulement à partir d'un fichier.
Tyler Collier
3
Vous pouvez simuler un fichier avec <<< comme dans: ssh user @ target "at now -f <<< 'my_comnads'"
Nico
6

Je pense que vous devrez combiner quelques-unes de ces réponses pour obtenir ce que vous voulez. Si vous utilisez nohup en conjonction avec le point-virgule et enveloppez le tout entre guillemets, vous obtenez:

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

qui semble fonctionner pour moi. Avec nohup, vous n'avez pas besoin d'ajouter le & à la commande à exécuter. De plus, si vous n'avez pas besoin de lire la sortie de la commande, vous pouvez utiliser

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

pour rediriger toutes les sorties vers / dev / null.


la source
5

Cela a fonctionné pour moi plusieurs fois:

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

Vous pouvez le faire comme ça ...

sudo /home/script.sh -opt1 > /tmp/script.out &
user889030
la source
Parfait, fonctionne avec une session PuTTY SSH. Je peux quitter et le script continue sur la machine. Je vous remercie.
Satria
1

En fait, chaque fois que j'ai besoin d'exécuter une commande sur une machine distante qui est compliquée, j'aime mettre la commande dans un script sur la machine de destination et simplement exécuter ce script en utilisant ssh.

Par exemple:

# simple_script.sh (located on remote server)

#!/bin/bash

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

Et puis je lance juste cette commande sur la machine source:

ssh user@ip "/path/to/simple_script.sh"
PaulT
la source
0

J'essayais de faire la même chose, mais avec la complexité supplémentaire que j'essayais de faire depuis Java. Donc, sur une machine exécutant java, j'essayais d'exécuter un script sur une autre machine, en arrière-plan (avec nohup).

À partir de la ligne de commande, voici ce qui a fonctionné: (vous n'aurez peut-être pas besoin du "-i keyFile" si vous n'en avez pas besoin pour ssh vers l'hôte)

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

Notez que sur ma ligne de commande, il y a un argument après le "-c", qui est tout entre guillemets. Mais pour que cela fonctionne à l'autre bout, il a toujours besoin des guillemets, j'ai donc dû y mettre des guillemets échappés.

De Java, voici ce qui a fonctionné:

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.

Il a fallu un peu d'essais et d'erreurs pour que cela fonctionne, mais cela semble bien fonctionner maintenant.

Randy Wilson
la source
0

Il m'a semblé assez pratique d'avoir une session tmux à distance en utilisant la tmux new -d <shell cmd>syntaxe comme ceci:

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

Cela lancera une nouvelle session sur l' elsewherehôte et la commande ssh sur la machine locale reviendra au shell presque instantanément. Vous pouvez ensuite ssh vers l'hôte distant et tmux attachvers cette session. Notez qu'il n'y a rien sur tmux local en cours d'exécution, seulement à distance!

De plus, si vous souhaitez que votre session persiste une fois le travail terminé, ajoutez simplement un lanceur de shell après votre commande, mais n'oubliez pas de mettre entre guillemets:

ssh someone@elsewhere 'tmux new -d "~/myscript.sh; bash"'
zebrilo
la source
0
YOUR-COMMAND &> YOUR-LOG.log &    

Cela devrait exécuter la commande et attribuer un identifiant de processus que vous pouvez simplement taper -f YOUR-LOG.log pour voir les résultats qui y sont écrits au fur et à mesure. vous pouvez vous déconnecter à tout moment et le processus se poursuivra

richprice316
la source
0

Vous pouvez le faire sans nohup:

ssh user@host 'myprogram >out.log 2>err.log &'
ijt
la source
-2

Je pense que c'est ce dont vous avez besoin: au début, vous devez installer sshpasssur votre machine. alors vous pouvez écrire votre propre script:

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
MLSC
la source
-3

Suivez d'abord cette procédure:

Connectez-vous à A en tant qu'utilisateur a et générez une paire de clés d'authentification. N'entrez pas de phrase secrète:

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

Utilisez maintenant ssh pour créer un répertoire ~ / .ssh en tant qu'utilisateur b sur B. (Le répertoire peut déjà exister, ce qui est bien):

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

Enfin, ajoutez la nouvelle clé publique de a à b @ B: .ssh / authorized_keys et entrez une dernière fois le mot de passe de b:

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

Vous pouvez désormais vous connecter à B en tant que b à partir de A en tant que sans mot de passe:

a@A:~> ssh b@B

alors cela fonctionnera sans entrer de mot de passe

ssh b @ B "répertoire cd / certains /; programme à exécuter &"

Kevin Duterne
la source
1
La question dit que dagorym a déjà configuré les clés pour ne pas nécessiter de mot de passe, mais il est toujours suspendu
Max Nanasy