Estoy intentando crear un comando que se comporte como un "enlace simbólico a través de ssh", es decir, llame a un script remoto como si se llamara localmente. Mi guión es:
#!/bin/zsh
if (( "$#" = 0 )); then
echo "Usage: $0 <number>" >&2; exit 1
fi
if ! [[ "$1" =~ '^[0-9]+$' ]]; then
echo "error: “$1” is not a valid number" >&2; exit 1
fi
Para esto usaré <(command)
, una sustitución de proceso que creará un quince con una ruta como /proc/self/fd/<n>
, redirigirá command
la salida estándar a él y evaluará esa ruta. fifo=<(echo 'hi!'); echo $fifo; cat $fifo
hará eco /proc/self/fd/14
(más o menos) y luego hi!
.
Así que esto debería funcionar, veamos si lo del “Uso” funciona. Guardaré este script en mi $PATH y lo ejecutaré por su nombre de archivo exec-remote
.
#!/bin/zsh
source <(ssh myserver 'cat bin/mycommand')
¡Casi! Esto da como resultado que el script remoto diga
Usage: /proc/self/fd/12 <number>
en lugar de
Usage: exec-remote <number>
… lo que significa que mientras se obtiene el código del script remoto, $0
se establece en la ruta quince del proceso de sustitución.
Pero el comando de zsh source
parece aceptar solo parámetros posicionales ( $@
):
#!/bin/zsh
source <(ssh myserver 'cat bin/mycommand') $0
…hará que mi guión diga:
error: “/proc/self/fd/12” is not a valid number
Entonces, ¿cómo puedo hacer que zsh ejecute mi código remoto y dejarlo $0
solo al hacerlo?
Respuesta1
Creo que source
sólo interfiere en cierto modo. Guarde lo siguiente (localmente) como exec-from-myserver
:
#!/bin/sh
name=${0##/}
exec zsh -c "$(ssh myserver "cat 'bin/$name'")" "$0" "$@"
Hágalo ejecutable y luego vincúlelo simbólicamente:
ln -s exec-from-myserver mycommand
ln -s exec-from-myserver foo-bar-baz
# etc.
(Nota: la cadena cat 'bin/whatever_name_you_chose'
seráanalizadoen el lado remoto. Los nombres con literal '
romperán el código o harán que se comporte mal; Incluso puedes realizar inyección de código nombrando enlaces simbólicos de cierta manera. Dado que eres tú quien elige los nombres, no es realmente crítico. Utilice nombres habituales y estará bien).
Ahora, si llama mycommand
, el script local exec
interpretará zsh
el control remoto bin/mycommand
y $0
en su contexto se establecerá en el valor útil de anterior (local) $0
. La persona que llama foo-bar-baz
intentará extraer e interpretar el control remoto bin/foo-bar-baz
. Ejemplos:
$ ./mycommand
Usage: ./mycommand <number>
$ # This was your remote script talking.
$ ./mycommand 1
$ # Executed without complaint.
$ ././mycommand
Usage: ././mycommand <number>
$ # As you can see the remote script is aware of its local name and path used.
$ ./foo-bar-baz
cat: bin/foo-bar-baz: No such file or directory
$ # This was the remote cat talking, only because there is no remote foo-bar-baz.
Notas:
- Un matiz en mi terminología: "el script remoto" existe en el lado remoto como un archivo, pero se interpreta localmente; "El gato remoto" es verdaderamente remoto.
exec-from-myserver
siempre usazsh -c
, el shebang en el script remoto se ignora por completo (su experimentosource
también lo ignoró).