Passer des variables dans la commande ssh distante

99

Je veux pouvoir exécuter une commande depuis ma machine en utilisant ssh et passer par la variable d'environnement $BUILD_NUMBER

Voici ce que j'essaye:

ssh pvt@192.168.1.133 '~/tools/myScript.pl $BUILD_NUMBER'

$BUILD_NUMBER est défini sur la machine effectuant l'appel ssh et comme la variable n'existe pas sur l'hôte distant, elle n'est pas récupérée.

Comment transmettre la valeur de $BUILD_NUMBER?

Fergal
la source
1
sans rapport avec Hudson, a supprimé l'étiquette. (Hudson crée juste la variable)
Peter Schuetze

Réponses:

188

Si tu utilises

ssh pvt@192.168.1.133 "~/tools/run_pvt.pl $BUILD_NUMBER"

au lieu de

ssh pvt@192.168.1.133 '~/tools/run_pvt.pl $BUILD_NUMBER'

votre shell interpolera le $BUILD_NUMBERavant d'envoyer la chaîne de commande à l'hôte distant.

sarnold
la source
8
Si quelqu'un DOIT utiliser des guillemets simples pour que la commande incluse dans les guillemets ne soit pas évaluée localement, alors ils devraient utiliser "'$ VARIABLE'". Exemple: ssh [email protected] '~ / tools / run_pvt.pl "' $ BUILD_NUMBER '"'
dr.doom
3
ne savait pas que bash réagit différemment avec des guillemets simples et doubles. Merci!
silgon
1
les développeurs du noyau Linux doivent brûler en enfer
goldstar
@goldstar, notez que la différence entre le comportement des guillemets simples et des guillemets doubles dans le shell est antérieure à Linux de plusieurs décennies.
sarnold
3
PSA: si votre chaîne contient une entrée utilisateur, c'est une très mauvaise idée, et pourrait vous ouvrir à des attaques par injection de code.
Brian McCutchon le
27

Les variables entre guillemets simples ne sont pas évaluées. Utilisez des guillemets doubles:

ssh pvt@192.168.1.133 "~/tools/run_pvt.pl $BUILD_NUMBER"

Le shell développera les variables entre guillemets, mais pas entre guillemets simples. Cela deviendra la chaîne souhaitée avant d'être passé à la sshcommande.

Stephen
la source
2

(Cette réponse peut sembler inutilement compliquée, mais elle est facilement extensible et robuste en ce qui concerne les espaces blancs et les caractères spéciaux, pour autant que je sache.)

Vous pouvez alimenter les données directement via l'entrée standard de la sshcommande et readcela depuis l'emplacement distant.

Dans l'exemple suivant,

  1. un tableau indexé est rempli (par commodité) avec les noms des variables dont vous souhaitez récupérer les valeurs du côté distant.
  2. Pour chacune de ces variables, nous donnons à ssh une ligne terminée par un zéro donnant le nom et la valeur de la variable.
  3. Dans la shhcommande elle-même, nous parcourons ces lignes pour initialiser les variables requises.
# Initialize examples of variables.
# The first one even contains whitespace and a newline.
readonly FOO=$'apjlljs ailsi \n ajlls\t éjij'
readonly BAR=ygnàgyààynygbjrbjrb

# Make a list of what you want to pass through SSH.
# (The “unset” is just in case someone exported
# an associative array with this name.)
unset -v VAR_NAMES
readonly VAR_NAMES=(
    FOO
    BAR
)

for name in "${VAR_NAMES[@]}"
do
    printf '%s %s\0' "$name" "${!name}"
done | ssh user@somehost.com '
    while read -rd '"''"' name value
    do
        export "$name"="$value"
    done

    # Check
    printf "FOO = [%q]; BAR = [%q]\n" "$FOO" "$BAR"
'

Production:

FOO = [$'apjlljs ailsi \n ajlls\t éjij']; BAR = [ygnàgyààynygbjrbjrb]

Si vous n'en avez pas besoin export, vous devriez pouvoir utiliser à la declareplace de export.

Une version vraiment simplifiée (si vous n'avez pas besoin de l'extensibilité, avez une seule variable à traiter, etc.) ressemblerait à:

$ ssh user@somehost.com 'read foo' <<< "$foo"
Alice M.
la source
2

La liste des variables d'environnement acceptées sur SSHD par défaut comprend LC_*. Donc:

LC_MY_BUILDN="1.2.3" ssh -o "SendEnv LC_MY_BUILDN" ssh-host 'echo $LC_MY_BUILDN'
1.2.3
Alex Stragies
la source
0

Comme indiqué précédemment, vous n'avez pas besoin de définir la variable d'environnement sur l'hôte distant. Au lieu de cela, vous pouvez simplement effectuer la méta-expansion sur l'hôte local et transmettre la valeur à l'hôte distant.

ssh pvt@192.168.1.133 '~/tools/run_pvt.pl $BUILD_NUMBER'

Si vous voulez vraiment définir la variable d'environnement sur l'hôte distant et l'utiliser, vous pouvez utiliser le envprogramme

ssh pvt@192.168.1.133 "env BUILD_NUMBER=$BUILD_NUMBER ~/tools/run_pvt.pl \$BUILD_NUMBER"

Dans ce cas, c'est un peu exagéré, et notez

  • env BUILD_NUMBER=$BUILD_NUMBER fait la méta-expansion sur l'hôte local
  • la BUILD_NUMBERvariable d'environnement distant sera utilisée par
    le shell distant
Gilles Gouaillardet
la source
0

Il est également possible de passer des variables d'environnement explicitement via ssh. Cela nécessite une configuration côté serveur, ce n'est donc pas une réponse universelle.

Dans mon cas, je voulais passer une clé de chiffrement du référentiel de sauvegarde à une commande sur le serveur de stockage de sauvegarde sans y avoir stocké cette clé, mais notez que toute variable d'environnement est visible dans ps ! La solution de passer la clé sur stdin fonctionnerait également, mais je l'ai trouvée trop lourde. Dans tous les cas, voici comment passer une variable d'environnement via ssh:

Sur le serveur, modifiez le sshd_configfichier, généralement /etc/ssh/sshd_configet ajoutez une AcceptEnvdirective correspondant aux variables que vous souhaitez transmettre. Voir man sshd_config. Dans mon cas, je souhaite passer des variables à la sauvegarde borg, j'ai donc choisi:

AcceptEnv BORG_*

Maintenant, sur le client, utilisez l' -o SendEnvoption pour envoyer des variables d'environnement. La ligne de commande suivante définit la variable d'environnement BORG_SECRET, puis la marque pour qu'elle soit envoyée à la machine client (appelée backup). Il printenvs'y exécute ensuite et filtre la sortie pour les variables BORG:

$ BORG_SECRET=magic-happens ssh -o SendEnv=BORG_SECRET backup printenv | egrep BORG
BORG_SECRET=magic-happens
TvE
la source
Vous pouvez «passer en contrebande» vos variables en utilisant les paramètres par défaut côté serveur, voir ma réponse . L'essentiel est que la configuration OpenSSHd par défaut inclut LC_*les variables autorisées à envoyer, alors utilisez simplement $LC_TvE_foo, ou $LC_BORG_SECRETassurez-vous simplement de ne pas "heurter" une variable intégrée.
Alex Stragies
-2

Échappez à la variable pour accéder aux variables en dehors de la session ssh: ssh [email protected] "~ / tools / myScript.pl \ $ BUILD_NUMBER"

Sarah Gruneisen
la source
2
Cela n'atteint pas ce que demande la question.
Patrick Trentin
2
du point de vue de la coque, '$FOO'équivaut à "\$FOO". la question était "comment passer une variable shell avec SSH?". Comme déjà indiqué par @PatrickTrentin, ce n'est pas une réponse correcte car BUILD_NUMBERla variable d'environnement n'est pas définie à distance.
Gilles Gouaillardet