web-dev-qa-db-fra.com

Comment puis-je exécuter un script local sur une machine distante et inclure des arguments?

J'ai écrit un script qui fonctionne bien lorsqu'il est exécuté localement:

./sysMole -time Aug 18 18

Les arguments "- time", "Aug", "18" et "18" sont passés avec succès sur le script.

Maintenant, ce script est conçu pour être exécuté sur une machine distante mais à partir d'un répertoire local sur la machine locale. Exemple:

ssh root@remoteServer "bash -s" < /var/www/html/ops1/sysMole

Cela fonctionne également très bien. Mais le problème se pose lorsque j'essaie d'inclure les arguments susmentionnés (- heure 18 août 18), par exemple:

ssh root@remoteServer "bash -s" < /var/www/html/ops1/sysMole -time Aug 18 18

Après avoir exécuté ce script, j'obtiens l'erreur suivante:

bash: cannot set terminal process group (-1): Invalid argument
bash: no job control in this Shell

S'il vous plaît, dites-moi ce que je fais mal, c'est très frustrant.

123
AllenD

Vous étiez assez proche de votre exemple. Cela fonctionne très bien lorsque vous l'utilisez avec des arguments tels que ceux-ci.

Exemple de script:

$ more ex.bash 
#!/bin/bash

echo $1 $2

Exemple qui fonctionne:

$ ssh serverA "bash -s" < ./ex.bash "hi" "bye"
hi bye

Mais il échoue pour ces types d'arguments:

$ ssh serverA "bash -s" < ./ex.bash "--time" "bye"
bash: --: invalid option
...

Que se passe-t-il?

Le problème que vous rencontrez est que l'argument, -time, ou --time dans mon exemple, est interprété comme un basculement vers bash -s. Vous pouvez pacifier bash en l'empêchant de prendre pour lui-même l'un des arguments de ligne de commande restants à l'aide de -- argument.

Comme ça:

$ ssh root@remoteServer "bash -s" -- < /var/www/html/ops1/sysMole -time Aug 18 18

Exemples

# 1:

$ ssh serverA "bash -s" -- < ./ex.bash "-time" "bye"
-time bye

# 2:

$ ssh serverA "bash -s" -- < ./ex.bash "--time" "bye"
--time bye

# 3:

$ ssh serverA "bash -s" -- < ./ex.bash --time "bye"
--time bye

# 4:

$ ssh  < ./ex.bash serverA "bash -s -- --time bye"
--time bye

NOTE: Juste pour qu'il soit clair que partout où la redirection apparaît sur la ligne de commande ne fait aucune différence, car ssh appelle un shell distant avec la concaténation de ses arguments de toute façon, la citation ne fait pas faire beaucoup de différence, sauf lorsque vous avez besoin de citer sur le shell distant comme dans l'exemple # 4:

$ ssh  < ./ex.bash serverA "bash -s -- '<--time bye>' '<end>'"
<--time bye> <end>
173
slm

Sur la gestion des arguments arbitraires

Si vous n'utilisez vraiment qu'une seule chaîne, par exemple. -time Aug 18 18, Alors vous pouvez simplement le coder en dur, et les réponses existantes vous indiquent comment procéder de manière adéquate. D'un autre côté, si vous devez passer des arguments inconnus (comme un message à afficher sur l'autre système ou le nom d'un fichier créé où les utilisateurs finaux pourraient contrôler son nom), alors plus de prudence est nécessaire.


Avec bash ou ksh comme /bin/sh

Si votre /bin/sh Distant est fourni par bash ou ksh, vous pouvez effectuer les opérations suivantes en toute sécurité avec une liste d'arguments non fiables, de sorte que même les noms malveillants (comme $(rm -rf $HOME).txt) peuvent être passés en tant qu'arguments en toute sécurité:

runRemote() {
  local args script

  script=$1; shift

  # generate eval-safe quoted version of current argument list
  printf -v args '%q ' "$@"

  # pass that through on the command line to bash -s
  # note that $args is parsed remotely by /bin/sh, not by bash!
  ssh user@remote-addr "bash -s -- $args" < "$script"
}

Avec tout compatible POSIX /bin/sh

Pour éviter les données d'arguments suffisamment malveillantes (tenter de tirer parti des citations non conformes à POSIX utilisées par printf %q Dans bash lorsque des caractères non imprimables sont présents dans la chaîne échappée) même avec un /bin/sh c'est baseline-POSIX (comme dash ou ash), ça devient un peu plus intéressant:

runRemote() {
  local script=$1; shift
  local args
  printf -v args '%q ' "$@"
  ssh user@remote-addr "bash -s" <<EOF

  # pass quoted arguments through for parsing by remote bash
  set -- $args

  # substitute literal script text into heredoc
  $(< "$script")

EOF
}

Utilisation (pour l'un ou l'autre des éléments ci-dessus)

Les fonctions données ci-dessus peuvent alors être invoquées comme:

# if your time should be three arguments
runRemote /var/www/html/ops1/sysMole -time Aug 18 18

...ou...

# if your time should be one string
runRemote /var/www/html/ops1/sysMole -time "Aug 18 18"
7
Charles Duffy

Mettez les commandes entre guillemets comme suit:

ssh myserver "date +\"Date: %Y%m%d %H:%M\";printf \"Uptime: \";uptime;printf \"uname: \";uname -a"
Date: 20200409 20:02
Uptime:  20:02:29 up 66 days, 55 min,  2 users,  load average: 0.06, 0.05, 0.08
uname: Linux zltcmtn23aecc1rx7322 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
Connection to 105.31.182.217 closed.
0
Richard