Definir $ 0 na fonte do zsh?

Definir $ 0 na fonte do zsh?

Estou tentando criar um comando que se comporte como um “link simbólico através de ssh”, ou seja, chame um script remoto como se fosse chamado localmente. Meu roteiro é:

#!/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 isso usarei <(command), uma substituição de processo que criará um fifo com um caminho como /proc/self/fd/<n>, redirecionará commando stdout de para ele e avaliará para esse caminho. fifo=<(echo 'hi!'); echo $fifo; cat $fifoirá ecoar /proc/self/fd/14(ou algo assim) e então hi!.

Então isso deve funcionar, vamos ver se a coisa de “Uso” funciona. Salvarei esse script em meu $PATH e o executarei pelo nome do arquivo exec-remote.

#!/bin/zsh
source <(ssh myserver 'cat bin/mycommand')

Quase! Isso resulta no script remoto dizendo

Usage: /proc/self/fd/12 <number>

em vez de

Usage: exec-remote <number>

… o que significa que, ao fornecer o código do script remoto, $0ele está definido para o caminho fifo da substituição do processo.

Mas o comando do zsh sourceparece aceitar apenas parâmetros posicionais ( $@):

#!/bin/zsh
source <(ssh myserver 'cat bin/mycommand') $0

… fará meu script dizer:

error: “/proc/self/fd/12” is not a valid number

Então, como posso fazer o zsh executar meu código remoto e deixá-lo $0sozinho ao fazê-lo?

Responder1

Acho que sourcesó atrapalha. Salve o seguinte (localmente) como exec-from-myserver:

#!/bin/sh
name=${0##/}
exec zsh -c "$(ssh myserver "cat 'bin/$name'")" "$0" "$@"

Torne-o executável e crie um link simbólico para ele:

ln -s exec-from-myserver mycommand
ln -s exec-from-myserver foo-bar-baz
# etc.

(Nota: a string cat 'bin/whatever_name_you_chose'seráanalisadono lado remoto. Nomes literais 'quebrarão o código ou farão com que ele se comporte mal; você pode até realizar injeção de código nomeando links simbólicos de uma determinada maneira. Como é você quem escolhe os nomes, isso não é realmente crítico. Use nomes normais e tudo ficará bem.)

Agora, se você ligar mycommand, o script local execinterpretará zsho remoto bin/mycommande $0em seu contexto será definido com o valor útil de previous (local) $0. A chamada foo-bar-baztentará extrair e interpretar o controle remoto bin/foo-bar-baz. Exemplos:

$ ./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:

  • Uma nuance na minha terminologia: "o script remoto" existe no lado remoto como um arquivo, mas é interpretado localmente; “o gato remoto” é verdadeiramente remoto.
  • exec-from-myserversempre usa zsh -c, o shebang no script remoto é completamente ignorado (sua experiência sourcetambém o ignorou).

informação relacionada