$0 in der zsh-Quelle festlegen?

$0 in der zsh-Quelle festlegen?

Ich versuche, einen Befehl zu erstellen, der sich wie ein „Symlink über SSH“ verhält, d. h. ein Remote-Skript aufruft, als ob es lokal aufgerufen würde. Mein Skript ist:

#!/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

Hierfür verwende ich <(command), eine Prozessersetzung, die ein FIFO mit einem Pfad wie erstellt /proc/self/fd/<n>, commanddie Standardausgabe von dorthin umleitet und die Auswertung anhand dieses Pfads vornimmt. Es fifo=<(echo 'hi!'); echo $fifo; cat $fifowird ein Echo /proc/self/fd/14(oder so ähnlich) ausgegeben und dann hi!.

Das sollte also funktionieren. Mal sehen, ob die Sache mit der „Verwendung“ funktioniert. Ich speichere dieses Skript in meinem $PATH und führe es über seinen Dateinamen aus exec-remote.

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

Fast! Das Ergebnis ist, dass das Remote-Skript sagt:

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

anstatt

Usage: exec-remote <number>

… was bedeutet, dass beim Abrufen des Codes des Remote-Skripts $0der FIFO-Pfad der Prozessersetzung eingestellt ist.

Aber der Befehl von zsh sourcescheint nur Positionsparameter ( $@) zu akzeptieren:

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

… lässt mein Skript sagen:

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

Wie kann ich also erreichen, dass zsh meinen Remote-Code ausführt, ohne $0ihn dabei zu verändern?

Antwort1

Ich denke, sourcedas ist nur ein Hindernis. Speichern Sie Folgendes (lokal) als exec-from-myserver:

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

Machen Sie es ausführbar und erstellen Sie dann einen symbolischen Link darauf:

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

(Hinweis: Die Zeichenfolge cat 'bin/whatever_name_you_chose'wirdanalysiertauf der Remote-Seite. Namen mit Literalwerten 'beschädigen den Code oder führen zu Fehlfunktionen. Sie können sogar Code-Injektion durchführen, indem Sie Symlinks auf eine bestimmte Weise benennen. Da Sie die Namen auswählen, ist dies nicht wirklich kritisch. Verwenden Sie normale Namen, dann ist alles in Ordnung.)

Wenn Sie jetzt aufrufen , interpretiert mycommanddas lokale Skript den Remote-Befehl und wird in seinem Kontext auf den nützlichen Wert von previous (local) gesetzt . Der Aufruf versucht, den Remote-Befehl abzurufen und zu interpretieren . Beispiele:execzshbin/mycommand$0$0foo-bar-bazbin/foo-bar-baz

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

Anmerkungen:

  • Eine Nuance in meiner Terminologie: „Das Remote-Skript“ existiert auf der Remote-Seite als Datei, wird aber lokal interpretiert; „die Remote-Cat“ ist wirklich remote.
  • exec-from-myserververwendet immer zsh -c, der Shebang im Remote-Skript wird vollständig ignoriert (Ihr Experiment mit sourcehat ihn ebenfalls ignoriert).

verwandte Informationen