Tengo un programa en un host remoto, cuya ejecución necesito automatizar. El comando ejecutar ese programa, en la misma máquina, se parece a esto:
/path/to/program -a file1.txt -b file2.txt
En este caso, file1.txt
y file2.txt
se usan para cosas completamente diferentes dentro del programa, por lo que no puedo simplemente cat
juntarlas. Sin embargo, en mi caso, el file1.txt
y file2.txt
que quiero pasar al programa solo existen en mi dispositivo, no en el host donde necesito ejecutar el programa. Sé que puedo alimentar al menos un archivo a través de SSH pasándolo stdin
:
cat file1.txt | ssh host.name /path/to/program -a /dev/stdin -b file2.txt
pero, dado que no se me permite almacenar archivos en el host, también necesito una forma de obtenerlos file2.txt
allí. Estoy pensando que podría ser posible mediante el abuso de las variables de entorno y el uso creativo de cat
y sed
juntos, pero no conozco las herramientas lo suficientemente bien como para entender cómo las usaría para lograr esto. ¿Es factible y cómo?
fuente
cat
ysed
no son la solución aquí.Respuestas:
Si los archivos proporcionados como argumentos para su programa son archivos de texto, y puede controlar su contenido (conoce una línea que no aparece dentro de ellos), puede usar varios documentos aquí:
Aquí
cat
hay un comando de muestra que toma nombres de archivos como argumentos. Podría ser en su lugar:Reemplace cada uno
EOT
con algo que no ocurra en cada uno de los archivos, respectivamente.fuente
dash
(el/bin/sh
en debian, ubuntu, etc.),busybox sh
el/bin/sh
de FreeBSD yyash
no use archivos temporales para documentos aquí. De hecho, lo he probado con un chroot de solo lectura. Por supuesto, los/dev/fd/
archivos tienen que estar disponibles, solo en un sistema de stock de FreeBSD/dev/fd/0-2
, por lofdescfs
que deben montarse/dev/fd
.U+001C
es "Information Separator Four" (separador de archivos, FS) y es ideal para este caso, aunque los archivos binarios pueden utilizarlo de manera coincidente. Por lo tanto, sugeriríaEOT="$(printf $'\x1c')"
en shells avanzados o de lo contrarioEOT="$(awk 'BEGIN{printf"%c",28}')"
para la compatibilidad. Deberá citarlo cuando lo coloque en su lugar, comoecho "$EOT$EOT$EOT"
(triplicado para reducir las probabilidades de que coincida con un archivo binario).tty
comando? A menos que me falte algo, ¿qué supongo que es posible?Tal vez no sea exactamente lo que quieres ... Pero tal vez considere enviar un tarball a través de la tubería abierta por ssh?
Dijiste eso:
Es posible que no tenga un directorio personal de escritura u otra ubicación conveniente para almacenar archivos a largo plazo, pero diría que es poco probable que no tenga una ubicación de escritura, incluso si hay un temporal
tmpfs
que estará disponible solo para su conexión particularMuchos programas (e incluso rutinas de libc) requieren una escritura
/tmp
, por lo que es muy probable que haya uno disponible para usted.Luego, puede usar un script que descomprima el tarball en un directorio temporal, ejecute su programa y limpie a través de la conexión ssh.
Algo como:
Esto podría necesitar un cuidado especial con las rutas de archivo y hay algunos casos de esquina para considerar (probar para ellos), pero el enfoque general debería funcionar.
Si no hay un directorio de escritura disponible, un posible enfoque sería modificar
program
para tomar un tarball como entrada única y descomprimir su contenido en la memoria. Por ejemplo, si seprogram
trata de un script de Python, el uso deltarfile
módulo incorporado fácilmente lograría algo así.fuente
/tmp/
y usarlo directamente.Si puede configurar un escucha TCP (puede ser un puerto más alto), entonces podría usar una segunda sesión SSH para establecer la segunda fuente de entrada
nc
.Ejemplo:
Hay este script en el servidor (
~/script.bash
):Y existen estos dos archivos localmente:
Ahora primero inicie la segunda fuente (
$serv
es el servidor):Y ejecute el comando apropiado:
fuente
Se estableció en un comentario que
/tmp
se puede escribir, así que simplemente copie previamente uno de los archivos:Esto también limpia el archivo copiado después de una ejecución exitosa (cambie
&&
a a;
si desea eliminarlo independientemente del éxito, pero luego tenga en cuenta que perderá el valor de salida).Si eso no es aceptable, propondría retoques
/path/to/program
o un contenedor que pueda separar los dos archivos de una sola secuencia de entrada como:Esto utiliza el separador de información ASCII cuatro (separador de archivos, FS) y lo ha triplicado para minimizar la posibilidad de que un archivo binario coincida con esa cadena. Su
tweaked_program
entonces dividir la entrada dado el separador y luego operar en los dos archivos guardados como variables.Por supuesto, si usa un lenguaje que tiene bibliotecas para manejar tarballs, un enfoque más seguro y limpio sería simplemente canalizar
tar
dicho código dessh
esta manera:Y
tweaked_program
descomprimiría y abriría el archivo, guardaría cada archivo en una variable diferente y luego ejecutaría laprogram
lógica del original en las variables.fuente
Si se le permite reenviar puertos
ssh
y tiene acceso awget
la máquina remota y abusybox
la máquina local, puede hacer algo como:(utilizando
cat
como programa de ejemplo que toma dos argumentos de archivo).Solo la capacidad de reenviar puertos
-R
es esencial; en lugar de hacer http, puede usar otros métodos, por ejemplo. si sunetcat
admite las opciones-d
y-N
:Puede haber formas de reemplazar el
<(...)
proceso si el shell de inicio de sesión en la máquina remota no es similar a ksh o bash.En general, esto no es demasiado bueno: un mejor conocimiento sobre el sistema / shells / config / permisos (que no ha proporcionado) podría permitir soluciones más inteligentes.
fuente
ACTUALIZACIÓN: Esto realmente no funciona, ssh tiene una idea muy clara de lo que significa stdin y stdout / stderr y realmente no permite que usurpando stderr lea de él. Eliminaré esta respuesta en unos días ya que no funciona. Gracias por la muy interesante discusión !!!
Desafortunadamente, no hay una excelente manera de hacer esto directamente, ya que el
ssh
cliente solo pasará los tres descriptores de archivo (stdin
,stdout
ystderr
) en el servidor y que no tiene disposiciones para pasar descriptores de archivos adicionales (que sería útil para este caso en particular .)(También tenga en cuenta que el protocolo SSH tiene disposiciones para pasar descriptores de archivo adicionales, solo que el
ssh
cliente no implementa una forma de usar esa característica. Teóricamente, extender el cliente con un parche sería suficiente para exponer esta característica).Una forma hacky de lograr lo que está buscando es usar el descriptor de archivo 2 (el
stderr
descriptor de archivo) para pasar el segundo archivo. Algo como:Esto debería funcionar, podría causar un problema si
program
intenta escribir en stderr. Puede evitar eso volviendo a hacer malabarismos con los descriptores de archivos en el extremo remoto antes de ejecutar el programa. Puede pasarfile2.txt
al descriptor de archivo 3 y volver a abrir stderr para duplicar stdout:fuente
3<&2
es un operador de shell Bourne, y sshd ejecuta el shell de inicio de sesión del usuario para interpretar el comando enviado por el cliente)SSH_MSG_CHANNEL_EXTENDED_DATA
mensajes con el tipo establecido enSSH_EXTENDED_DATA_STDERR
. Puedes leer todo aquí