J'ai un programme sur un hôte distant, dont j'ai besoin d'automatiser l'exécution. La commande exécute ce programme, sur la même machine, ressemble à ceci:
/path/to/program -a file1.txt -b file2.txt
Dans ce cas, file1.txt
et file2.txt
sont utilisés pour des choses entièrement différentes dans le programme, donc je ne peux pas simplement cat
les faire ensemble. Cependant, dans mon cas, le file1.txt
et file2.txt
que je souhaite transmettre au programme n'existent que sur mon appareil, pas sur l'hôte où j'ai besoin d'exécuter le programme. Je sais que je peux alimenter au moins un fichier via SSH en le passant par stdin
:
cat file1.txt | ssh host.name /path/to/program -a /dev/stdin -b file2.txt
mais, comme je ne suis pas autorisé à stocker des fichiers sur l'hôte, j'ai également besoin d'un moyen d'y accéder file2.txt
. Je pense que cela pourrait être possible grâce à l'abus des variables d'environnement et à l'utilisation créative de cat
et sed
ensemble, mais je ne connais pas suffisamment les outils pour comprendre comment je les utiliserais pour y parvenir. Est-ce faisable et comment?
la source
cat
etsed
ne sont pas la solution ici.Réponses:
Si les fichiers donnés comme arguments à votre programme sont des fichiers texte, et que vous êtes capable de contrôler leur contenu (vous connaissez une ligne qui ne s'y trouve pas), vous pouvez utiliser plusieurs documents ici:
Voici
cat
un exemple de commande qui prend les noms de fichiers comme arguments. Ce pourrait être à la place:Remplacez chacun
EOT
par quelque chose qui ne se produit pas dans chacun des fichiers, respectivement.la source
dash
(le/bin/sh
debian, ubuntu, etc.),busybox sh
le/bin/sh
de FreeBSD etyash
ne pas utiliser les fichiers temporaires pour ici-documents. Je l'ai testé avec un chroot en lecture seule. Bien sûr, les/dev/fd/
fichiers doivent être disponibles - sur un système FreeBSD d'origine seulement/dev/fd/0-2
, ilsfdescfs
doivent donc être montés/dev/fd
.U+001C
est "Information Separator Four" (séparateur de fichiers, FS) et est idéal dans ce cas, bien que les fichiers binaires puissent en faire usage par hasard. Par conséquent, je suggèreEOT="$(printf $'\x1c')"
dans des shells avancés ou bienEOT="$(awk 'BEGIN{printf"%c",28}')"
pour des raisons de compatibilité. Vous devrez le citer lorsque vous le mettrez en place, tel queecho "$EOT$EOT$EOT"
(triplé pour réduire les chances de faire correspondre un fichier binaire).tty
commande? À moins que je manque quelque chose - ce qui, je suppose, est possible?Peut-être pas exactement ce que vous voulez ... Mais pensez peut-être à envoyer une archive tar à travers le tuyau ouvert par ssh?
Vous avez dit que:
Il est possible que vous ne disposiez pas d'un répertoire de base accessible en écriture ou d'un autre emplacement pratique pour stocker des fichiers à long terme, mais je dirais qu'il est peu probable que vous ne disposiez pas d'un emplacement accessible en écriture, même si un temporaire
tmpfs
qui ne sera disponible que pour votre connexion particulière.De nombreux programmes (et même des routines libc) nécessitent une écriture
/tmp
, il est donc très probable que l'un d'entre eux soit disponible.Ensuite, vous pouvez utiliser un script qui décompactera l'archive tar dans un répertoire temporaire, exécutera votre programme et nettoiera via la connexion ssh.
Quelque chose comme:
Cela peut nécessiter des précautions supplémentaires avec les chemins de fichiers et il y a quelques cas d'angle à considérer (testez-les), mais l'approche générale devrait fonctionner.
Si aucun répertoire accessible en écriture n'est disponible, une approche possible serait de modifier
program
pour prendre une archive tar comme entrée unique et décompresser son contenu en mémoire. Par exemple, siprogram
c'est un script Python, alors utiliser letarfile
module intégré accomplirait facilement quelque chose comme ça.la source
/tmp/
et de l'utiliser directement.Si vous pouvez définir un écouteur TCP (il peut s'agir d'un port supérieur), vous pouvez utiliser une deuxième session SSH pour établir la deuxième source d'entrée avec
nc
.Exemple:
Il y a ce script sur le serveur (
~/script.bash
):Et il y a ces deux fichiers localement:
Maintenant, démarrez d'abord la deuxième source (
$serv
c'est le serveur):Et exécutez la commande appropriée:
la source
Il a été établi dans un commentaire qui
/tmp
est accessible en écriture, donc il suffit de copier sur l' un des fichiers au préalable:Cela nettoie également le fichier copié après une exécution réussie (remplacez-le
&&
par a;
si vous souhaitez le supprimer indépendamment de la réussite, mais notez ensuite que vous perdrez la valeur de sortie).Si ce n'est pas acceptable, je proposerais de bricoler avec
/path/to/program
ou un wrapper pour cela qui peut séparer les deux fichiers d'un seul flux d'entrée tel que:Cela utilise le séparateur d'informations ASCII quatre (séparateur de fichiers, FS) et l'a triplé afin que nous minimisions les chances qu'un fichier binaire contienne par hasard cette chaîne. Vous diviseriez
tweaked_program
ensuite l'entrée en fonction du séparateur, puis opéreriez sur les deux fichiers enregistrés en tant que variables.Bien sûr, si vous utilisez un langage qui possède des bibliothèques pour gérer les tarballs, une approche plus sûre et plus propre serait simplement de canaliser
tar
dans un tel codessh
comme ceci:Et vous
tweaked_program
décompressez et ouvrez l'archive, enregistrez chaque fichier dans une variable différente, puis exécutez laprogram
logique d'origine sur les variables.la source
Si vous êtes autorisé à transférer des ports
ssh
, et que vous avez accès àwget
sur la machine distante et àbusybox
la machine locale, vous pouvez faire quelque chose comme:(en utilisant
cat
comme exemple de programme qui prend deux arguments de fichier).Seule la possibilité de transférer des ports via
-R
est essentielle - au lieu de faire http, vous pouvez utiliser d'autres méthodes, par exemple. si votrenetcat
prend en charge les options-d
et-N
:Il peut y avoir des moyens de remplacer les
<(...)
substitutions de processus si le shell de connexion sur la machine distante n'est pas de type ksh ou bash.Dans l'ensemble, ce n'est pas trop grand - une meilleure connaissance du système / shells / config / permissions exact (que vous n'avez pas fourni) pourrait permettre des solutions plus intelligentes.
la source
MISE À JOUR: Cela ne fonctionne pas vraiment, ssh a une idée très précise de ce que stdin et stdout / stderr signifient et ne permet pas vraiment d'usurper stderr pour en lire. Je supprimerai cette réponse dans quelques jours car cela ne fonctionne pas. Merci pour la discussion très intéressante !!!
Malheureusement, il n'y a pas un excellent moyen de le faire directement, car le
ssh
client ne transmettra que les trois descripteurs de fichiers (stdin
,stdout
etstderr
) au serveur et il n'a pas de dispositions pour transmettre des descripteurs de fichiers supplémentaires (ce qui serait utile pour ce cas d'utilisation particulier). .)(Notez également que le protocole SSH a des dispositions pour passer des descripteurs de fichiers supplémentaires, seul le
ssh
client n'implémente pas un moyen d'utiliser cette fonctionnalité. Théoriquement, étendre le client avec un correctif serait suffisant pour exposer cette fonctionnalité.)Une manière hacky d'accomplir ce que vous cherchez est d'utiliser le descripteur de fichier 2 (le
stderr
descripteur de fichier) pour passer le deuxième fichier. Quelque chose comme:Cela devrait fonctionner, cela pourrait provoquer un problème si vous
program
essayez d'écrire sur stderr. Vous pouvez contourner cela en jonglant avec les descripteurs de fichiers sur l'extrémité distante avant d'exécuter le programme. Vous pouvez passerfile2.txt
au descripteur de fichier 3 et rouvrir stderr pour mettre en miroir stdout:la source
3<&2
est un opérateur de shell Bourne, et sshd exécute le shell de connexion de l'utilisateur pour interpréter la commande envoyée par le client)SSH_MSG_CHANNEL_EXTENDED_DATA
messages de type défini surSSH_EXTENDED_DATA_STDERR
. Vous pouvez lire le tout ici