¿Establecer $0 en la fuente de zsh?

¿Establecer $0 en la fuente de zsh?

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á commandla salida estándar a él y evaluará esa ruta. fifo=<(echo 'hi!'); echo $fifo; cat $fifohará 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, $0se establece en la ruta quince del proceso de sustitución.

Pero el comando de zsh sourceparece 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 $0solo al hacerlo?

Respuesta1

Creo que sourcesó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 execinterpretará zshel control remoto bin/mycommandy $0en su contexto se establecerá en el valor útil de anterior (local) $0. La persona que llama foo-bar-bazintentará 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-myserversiempre usa zsh -c, el shebang en el script remoto se ignora por completo (su experimento sourcetambién lo ignoró).

información relacionada