Solución
Reuniendo mucha información de varias fuentes diferentes, esto es lo que se me ocurrió.
Daemon local
Desde la computadora local (OSX), configure un demonio para escuchar en un puerto específico, a través de launchd
(vea los enlaces a continuación). El proceso del daemon simplemente llamará a pbcopy
, que tomará todo lo que se pase a través de STDIN
y lo colocará en el portapapeles. Para hacer esto necesita configurar un archivo launchd
plist. El mío se veía así:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>local.pbcopy.9999</string>
<key>UserName</key>
<string>joe</string>
<key>Program</key>
<string>/usr/bin/pbcopy</string>
<key>StandardOutPath</key>
<string>/tmp/pb9999.out</string>
<key>StandardErrorPath</key>
<string>/tmp/pb9999.err</string>
<key>Sockets</key>
<dict>
<key>Listeners</key>
<dict>
<key>SockNodeName</key>
<string>localhost</string>
<key>SockServiceName</key>
<string>9999</string>
</dict>
</dict>
<key>inetdCompatibility</key>
<dict>
<key>Wait</key>
<false/>
</dict>
</dict>
</plist>
Por convención, el nombre del archivo plist debe ser el nombre de la etiqueta con .plist
anexado, por lo que para el ejemplo anterior, sería local.pbcopy.9999.plist
. Si desea utilizar un puerto que no sea 9999, simplemente cámbielo en todas partes (teniendo en cuenta que debería estar por encima de 1024 y no debería ser un puerto conocido que podría estar usando). Una vez que tienes las cosas funcionando, puedes eliminar las claves y cadenas StandardOutPath
y StandardErrorPath
, ya que solo son necesarias para la depuración.
Para cargar el demonio, ejecute el siguiente comando:
$ launchctl load local.pbcopy.9999.plist
Puede ver que está cargado o eliminarlo con los siguientes comandos:
$ launchctl list local.pbcopy.9999
$ launchctl remove local.pbcopy.9999
Si desea que esto se cargue cada vez que inicie sesión, coloque el archivo plist en el directorio ~/Library/LaunchAgents
.
Nota: deberá configurar esto en cada host local en el que desee que funcione.
Reenvío de puertos SSH
Debido a que podría estar accediendo a la máquina remota desde varias computadoras locales diferentes, no puedo programar el envío de los datos de la máquina remota a un host específico. Para hacer que esto sea lo menos doloroso y dinámico posible, he usado el reenvío de puertos SSH para crear un enlace dinámico desde la máquina remota a la computadora local (el cómo y el por qué están más allá de esta respuesta; consulte a continuación para obtener más información) . Específicamente, creo un enlace desde el puerto 9997 de las máquinas remotas al puerto 9999 de la computadora local, que ahora tiene un demonio escuchando en él, gracias a las cosas launchd
anteriores. Podría usar el puerto 9999 tanto en la máquina remota como en la computadora local, pero no es necesario.
Para configurar este túnel, ejecute el siguiente comando:
$ ssh -R 9997:localhost:9999 [email protected]
Puede hacer el control remoto en varias máquinas remotas diferentes con el mismo comando y todo funcionará como se espera. Puede hacer el control remoto en la misma máquina remota varias veces con el mismo comando, y funcionará como se espera; vea la nota abajo.
Si no tiene ganas de escribir -R 9997:localhost:9999
en cada invocación de SSH que realice, puede poner la definición de reenvío remoto en el archivo de configuración de SSH para hacerlo automáticamente. Aquí hay un ejemplo de mi archivo ~/.ssh/config
:
Host ufo*
RemoteForward 9997 localhost:9999
Con eso, cada vez que SSH a un host cuyo nombre comience por 'ufo', el reenvío remoto desde 9997 a localhost: 9999 se configurará automáticamente. Consulte el enlace de la página del manual del archivo de configuración a continuación para obtener más opciones.
Enviando datos
En el extremo remoto, uso netcat
para enviar el contenido deseado al demonio que escucha.
$ date | nc localhost 9997
Puedes ponerte tan complicado como quieras:
$ nc localhost 9997 <<EOF
> 'ls -ld *'
> 'date'
> EOF
Incluso puedes decidir dinámicamente si enviar o no datos, según si alguien está escuchando o no (probablemente haya una forma más eficiente de hacerlo, pero funciona):
#!/bin/bash
cnt='(netstat -lnptu 2>/dev/null) | grep 127.0.0.1:9999 | grep -v grep | wc -l'
if [[ $cnt -eq 1 ]]; then
date | nc localhost 9999
fi
Observaciones & Advertencias
Cosas que noté:
-
pbcopy
juega bien con Copy'em Paste
- si inicia más de una sesión SSH con el mismo reenvío de puerto remoto a la misma máquina remota, solo la primera tendrá algún efecto; no se informarán errores de tipo "puerto duplicado" en ninguno de los extremos
- de manera similar, si realiza el acceso remoto desde varias computadoras locales diferentes a la misma máquina remota usando el mismo puerto remoto (por ejemplo, 9997), solo la primera tendrá algún efecto
Enlaces de referencia