Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Exporter une fonction pour la lancer sur un hôte distant via ssh

22 réponses
Avatar
Francois Lafont
Bonsoir à tous,

D'après mes recherches, ce que je veux faire n'a pas l'air possible mais
bon je pose quand même la question :

Voici un petit code bash qui ne marche pas :

----------------------------------------
#!/bin/bash

fct ()
{
echo "Ma super fonction qui fait plein de trucs..."
# etc.
# Peu importe le contenu de fct
}

export -f fct

ssh root@HOTE-DISTANT bash -c 'fct arg1 arg2'
----------------------------------------

Je misais beaucoup d'espoir sur le « export » mais ça ne change rien au
problème, quand « bash -c 'fct arg1 arg2' » est exécuté sur l'hôte
distant, j'ai alors le message me disant que fct est introuvable. Bref,
l'export ne marche pas et ftc est inconnue aux yeux de l'hôte distant.

Savez-vous comme faire marcher le code ci-dessus ? Peut-être une option
magique du côté de ssh ?

Je précise qu'on voit sur le Web des solutions comme ça :

----------------------------------------
fct="
echo \"Ma super fonction qui fait plein de trucs...\"
# etc.
"

ssh root@HOTE-DISTANT bash -c "'$fct'"
----------------------------------------

Mais je ne me résoudrai pas faire comme ça car :

- je perds la coloration syntaxique quand j'écris le contenu de fct et
ça c'est vraiment trop horrible.
- en plus il faut que je m'amuse à échapper tous les ", c'est vraiment
pénible.

Je pourrais faire ça aussi :

----------------------------------------
ssh root@HOTE-DISTANT bash -c < /un/fichier/externe
----------------------------------------

mais du coup je me trimballe deux fichiers et ça ne me plaît pas non plus.

Voilà, j'aimerais vraiment arriver à faire fonctionner le premier code
modulo des petits changements bien sûr puisqu'en l'état il ne fonctionne
pas.

Merci d'avance pour vos lumières.

--
François Lafont

10 réponses

1 2 3
Avatar
Luc.Habert.00__arjf
Francois Lafont :

fct ()
{
echo "Ma super fonction qui fait plein de trucs..."
# etc.
# Peu importe le contenu de fct
}

export -f fct

ssh bash -c 'fct arg1 arg2'



Le « export -f fct » a pour effet de définir une variable d'environnement
qui contient un truc qui ressemble au code source la fonction fct. Quand on
lance un bash avec une telle définition dans l'environnement, ce dernier la
reconnait et effectue la définition de fonction comme si tu l'avais tapée.
Donc on peut s'en sortir en transmettant $fct à travers ssh, pour le
remettre dans l'environnement à l'autre bout. Maintenant, il faut voir
comment faire cette transmission.

SSH a un mécanisme pour ça, mais malheureusement, il faut lister sur le
client et le serveur (et pour ce dernier dans la config du sshd) la liste
des variables autorisées (connerie de paranoia qui stérilise uneb feature
utile). Si tu controles le serveur, tu peux ajouter quelques noms de
fonction avec l'option AcceptEnv du sshd_config. Sinon, tu peux toujours
regarder si ils n'ont pas autorisé quelques variables style LANG, et
détourner l'une d'entre elles, en espérant que bash ne les ignore pas. Côté
client, il faut mettre « -o 'SendEnv fct' ».

Sinon, il faut bricoler.

ATTENTION: se munir d'un sac à vomi avant de lire la suite.

Je propose:

sh -c 'echo "$fct"' | mimencode | ssh 'fct=`mimencode -u`; export fct; exec bash -c fct'

Le sh -c 'echo "$fct"', c'est parce que bash fait semblant que fct n'est pas
dans l'env, donc il faut le gruger. Le coup de mimencode est sans doute
overkill, mais tant que j'y étais à grotesquifier, j'ai voulu me la jouer
safe.
Avatar
Francois Lafont
Le 13/12/2012 01:15, Luc Habert a écrit :

Le « export -f fct » a pour effet de définir une variable d'environnement
qui contient un truc qui ressemble au code source la fonction fct. Quand on
lance un bash avec une telle définition dans l'environnement, ce dernier la
reconnait et effectue la définition de fonction comme si tu l'avais tapée.
Donc on peut s'en sortir en transmettant $fct à travers ssh, pour le
remettre dans l'environnement à l'autre bout. Maintenant, il faut voir
comment faire cette transmission.

SSH a un mécanisme pour ça, mais malheureusement, il faut lister sur le
client et le serveur (et pour ce dernier dans la config du sshd) la liste
des variables autorisées (connerie de paranoia qui stérilise uneb feature
utile). Si tu controles le serveur, tu peux ajouter quelques noms de
fonction avec l'option AcceptEnv du sshd_config. Sinon, tu peux toujours
regarder si ils n'ont pas autorisé quelques variables style LANG, et
détourner l'une d'entre elles, en espérant que bash ne les ignore pas. Côté
client, il faut mettre « -o 'SendEnv fct' ».



Ok. Avec ces options ça marche mais j'ai un souci avec la gestion des
arguments :

----------------------------------------
~$ F () { echo "Appel de F"; }
~$ export -f F
~$ ssh -o 'SendEnv F' bash -c F
Appel de F
----------------------------------------

Jusque là tout va bien. Mais si je veux que F gère des arguments alors
là ça ne va plus :

----------------------------------------
~$ F () { echo "|$1|$2|"; }
~$ export -f F
~$ ssh -o 'SendEnv F' bash -c F
|||

# Mais pourtant comme ci-dessous, ça marche :

~$ bash -c 'F arg1 arg2'
|arg1|arg2|
----------------------------------------

Quelle est la subtilité là dedans ?

Sinon, il faut bricoler.

ATTENTION: se munir d'un sac à vomi avant de lire la suite.



:-)

Je propose:

sh -c 'echo "$fct"' | mimencode | ssh 'fct=`mimencode -u`; export fct; exec bash -c fct'

Le sh -c 'echo "$fct"', c'est parce que bash fait semblant que fct n'est pas
dans l'env, donc il faut le gruger. Le coup de mimencode est sans doute
overkill, mais tant que j'y étais à grotesquifier, j'ai voulu me la jouer
safe.



Je le méditerai plus tard. Mais effectivement ça n'a pas l'air jojo.
Mais je me doutais un peu qu'il n'y avait pas de moyen « propre » pour
faire ce que je voulais.

Merci pour ton aide.

--
François Lafont
Avatar
Francois Lafont
Le 13/12/2012 01:15, Luc Habert a écrit :

sh -c 'echo "$fct"' | mimencode | ssh 'fct=`mimencode -u`; export fct; exec bash -c fct'

Le sh -c 'echo "$fct"', c'est parce que bash fait semblant que fct n'est pas
dans l'env



En effet :

~$ F () { echo "Appel de F"; }
~$ export -f F
~$ bash -c 'echo "$F"'
$ sh -c 'echo "$F"'
() { echo "Appel de F"
}

Mais pourquoi bash « fait semblant » que F n'est pas l'environnement
alors que sh (dash chez moi) non ?

--
François Lafont
Avatar
Luc.Habert.00__arjf
Francois Lafont :

Jusque là tout va bien. Mais si je veux que F gère des arguments alors
là ça ne va plus :

----------------------------------------
~$ F () { echo "|$1|$2|"; }
~$ export -f F
~$ ssh -o 'SendEnv F' bash -c F
|||



Il faut juste les lui passer:

ssh -o 'SendEnv F' 'bash -c '''F arg1 arg2''
Avatar
Luc.Habert.00__arjf
Francois Lafont :

Mais pourquoi bash « fait semblant » que F n'est pas l'environnement



Parce que.

alors que sh (dash chez moi) non ?



export -f est un bashisme que dash ne connait pas. Dash ne joue pas a ce
genre de subtilites avec son env.
Avatar
Francois Lafont
Le 13/12/2012 03:06, Luc Habert a écrit :
Francois Lafont :

Jusque là tout va bien. Mais si je veux que F gère des arguments alors
là ça ne va plus :

----------------------------------------
~$ F () { echo "|$1|$2|"; }
~$ export -f F
~$ ssh -o 'SendEnv F' bash -c F
|||



Il faut juste les lui passer:



Désolé, j'avais fais une erreur de copier-coller, c'était ça que je vous
écrire :

~$ ssh -o 'SendEnv F' bash -c 'F arg1 arg2'
|||

J'ai bien passé mes 2 arguments à F, non ?

ssh -o 'SendEnv F' 'bash -c '''F arg1 arg2''



Chez moi, ça donne :

bash: -c: ligne 0: Caractère de fin de fichier (EOF) prématuré lors de
la recherche du « ' » correspondant
bash: -c: ligne1: Erreur de syntaxe : fin de fichier prématurée.

J'avoue ne pas comprendre la présence des mais j'imagine qu'il y a une
raison.

--
François Lafont
Avatar
Nicolas George
Francois Lafont , dans le message
<50c99642$0$1852$, a écrit :
~$ ssh -o 'SendEnv F' bash -c 'F arg1 arg2'
|||
J'ai bien passé mes 2 arguments à F, non ?



Non, tu les as passés à bash. Il faut savoir que ssh ne passe pas une liste
d'arguments, il passe une ligne de commande, qui est exécutée par un shell à
l'arrivée. Donc :

ssh [options] bash -c 'F arg1 arg2'
ssh [options] 'bash -c F arg1 arg2'
ssh [options] bash -c F arg1 arg2

sont tous les trois équivalents (tant qu'il n'y a pas de caractères
spéciaux), et c'est celui du milieu qui traduit le mieux ce qui se passe. À
l'arrivée, tu as la ligne de commande « bash -c F arg1 arg2 » qui est
exécutée. Dans ce cas, bash exécute la commande F, avec $0 qui vaut arg1 et
$1 qui vaut arg2, mais comme ils ne sont pas utilisés (le $1 sera caché par
celui de F à l'appel) ça ne sert à rien.

J'ai vraiment l'impression que tu cherches à faire quelque chose de trop
compliqué. C'est souvent le cas quand on débute, on se focalise sur une
solution qui avait l'air évidente au début en perdant de vue le but global.
Avatar
Luc.Habert.00__arjf
Francois Lafont :

ssh -o 'SendEnv F' 'bash -c '''F arg1 arg2''



Chez moi, ça donne :

bash: -c: ligne 0: Caractère de fin de fichier (EOF) prématuré lors de
la recherche du « ' » correspondant
bash: -c: ligne1: Erreur de syntaxe : fin de fichier prématurée.



Beuh, chez moi ça marche. Tu as bien copier-collé?

J'avoue ne pas comprendre la présence des mais j'imagine qu'il y a une
raison.



Mon but est de passer en argument à ssh la ligne de commande

bash -c 'F arg1 arg2'

. Si je la met juste entre '', ça louze parce que j'ai des ' à l'intérieur.
La solution consiste à remplacer chaque ' intérieur par ''' ce qui veut
dire:
- premier ' ferme la string
- ' un ' echappé pour qu'il ne soit pas interprété par le shell
- deuxième ' on réouvre la string.

J'aurais pu mettre "bash -c 'F arg1 arg2'", ça serait revenu au même ici,
mais je n'aime pas parce que ça autorise les évaluations de variables et de `.
Avatar
Francois Lafont
Le 13/12/2012 12:13, Nicolas George a écrit :
Francois Lafont , dans le message
<50c99642$0$1852$, a écrit :
~$ ssh -o 'SendEnv F' bash -c 'F arg1 arg2'
|||
J'ai bien passé mes 2 arguments à F, non ?



Non, tu les as passés à bash. Il faut savoir que ssh ne passe pas une liste
d'arguments, il passe une ligne de commande, qui est exécutée par un shell à
l'arrivée. Donc :

ssh [options] bash -c 'F arg1 arg2'
ssh [options] 'bash -c F arg1 arg2'
ssh [options] bash -c F arg1 arg2

sont tous les trois équivalents (tant qu'il n'y a pas de caractères
spéciaux), et c'est celui du milieu qui traduit le mieux ce qui se passe. À
l'arrivée, tu as la ligne de commande « bash -c F arg1 arg2 » qui est
exécutée. Dans ce cas, bash exécute la commande F, avec $0 qui vaut arg1 et
$1 qui vaut arg2, mais comme ils ne sont pas utilisés (le $1 sera caché par
celui de F à l'appel) ça ne sert à rien.



Ah, ok j'ai compris. Merci pour les explications. Du coup, un truc comme
ça fonctionne comme je l'attends :

ssh -o 'SendEnv F' "bash -c 'F arg1 arg2'"

C'est quand même sioux cette subtilité entre :

- ce ne sont pas des arguments que prend ssh
- mais c'est une "ligne de commandes"

Comment le savoir à l'avance ? Est-ce que par exemple le synopsis de la
commande ssh (dans la page man) me permet de le savoir à l'avance ?

Par exemple la commande sudo n'a pas l'air de fonctionner ainsi (mais je
n'en suis pas sûr).

J'ai vraiment l'impression que tu cherches à faire quelque chose de trop
compliqué. C'est souvent le cas quand on débute, on se focalise sur une
solution qui avait l'air évidente au début en perdant de vue le but global.



C'est fort possible. Je suis bien sûr ouvert à toute remarque.

En fait, je souhaite pouvoir exécuter des scripts sur des machines
distantes le tout à partir d'une machine A, sachant que les scripts sont
stockés dans la machine A. Il s'agit de pouvoir me faire des petits
scripts « maison » de supervision avec un logiciel qui s'appelle shinken
et que j'essaye de découvrir.

Pour l'instant, j'ai deux scripts distincts : le-script-à-exécuter et le
script qui contient « ssh root@$HOTE bash < le-script-à-exécuter ». Mon
bout était de les faire fusionner en un seul script. Je crois savoir
qu'il existe pas mal d'outils pour faire tout ça mais le côté petit
script de supervision fait maison me plaisait bien. Ceci étant j'ai sans
doute tort...

Voilà, vous savez tout. ;-)

--
François Lafont
Avatar
Francois Lafont
Le 13/12/2012 03:08, Luc Habert a écrit :

Mais pourquoi bash « fait semblant » que F n'est pas l'environnement



Parce que.

alors que sh (dash chez moi) non ?



export -f est un bashisme que dash ne connait pas. Dash ne joue pas a ce
genre de subtilites avec son env.



Mais dash ne permet pas d'exporter une fonction ?

D'après mon petit test en dash, on dirait pas :

-----------------------------------
~$ dash
$ F () {
echo $1--$2
}


$ dash -c 'F a b'
dash: F: not found
$ export F
$ dash -c 'F a b'
dash: F: not found
-----------------------------------


--
François Lafont
1 2 3