¿Cómo copio al portapapeles OSX desde un shell remoto usando iTerm2?

3

Utilizando iTerm2, comienzo una sesión SSH interactiva en una máquina Linux remota (donde pbcopy no está disponible). En la máquina Linux remota me gustaría capturar la salida de algún comando arbitrario (por ejemplo, ls *.foo ), y hacer que aparezca mágicamente en mi portapapeles OSX, de modo que cuando golpee + v aparece en cualquier aplicación OSX que acabo de pegar. es posible? He probado los códigos de escape mencionados en la página doc iTerm2 y no puedo Haz que funcionen.

    
pregunta Joe Casadonte 14.10.2016 - 20:27

2 respuestas

3

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

respondido por el Joe Casadonte 21.10.2016 - 17:08
0

Puedes hacer esto

ssh -ttt user@location "ksh -c 'ls *'" | pbcopy
    
respondido por el fd0 15.10.2016 - 15:12

Lea otras preguntas en las etiquetas