![zsh のソースで $0 を設定しますか?](https://rvso.com/image/1586953/zsh%20%E3%81%AE%E3%82%BD%E3%83%BC%E3%82%B9%E3%81%A7%20%240%20%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%97%E3%81%BE%E3%81%99%E3%81%8B%3F.png)
私は「SSH 経由のシンボリックリンク」のように動作するコマンド、つまり、ローカルで呼び出されたかのようにリモート スクリプトを呼び出すコマンドを作成しようとしています。私のスクリプトは次のとおりです。
#!/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
このため、私は を使用します。これは、 のようなパスを持つ fifo を作成し、の stdout をそれにリダイレクトし、そのパスを評価する<(command)
プロセス置換です。 は (または同様の)をエコーし、次に を実行します。/proc/self/fd/<n>
command
fifo=<(echo 'hi!'); echo $fifo; cat $fifo
/proc/self/fd/14
hi!
これでうまくいくはずです。「使用方法」が機能するかどうか確認してみましょう。このスクリプトを $PATH に保存し、ファイル名で実行しますexec-remote
。
#!/bin/zsh
source <(ssh myserver 'cat bin/mycommand')
ほぼ完了です!リモートスクリプトは次のように表示されます
Usage: /proc/self/fd/12 <number>
の代わりに
Usage: exec-remote <number>
…つまり、リモート スクリプトのコードをソースするときに、$0
プロセス置換の FIFO パスが設定されます。
しかし、zsh のsource
コマンドは位置パラメータ ( ) のみを受け入れるようです$@
。
#!/bin/zsh
source <(ssh myserver 'cat bin/mycommand') $0
…スクリプトでは次のように記述します:
error: “/proc/self/fd/12” is not a valid number
では、リモート コードを実行したまま zsh を実行するにはどうすれば$0
よいのでしょうか?
答え1
source
邪魔になるだけだと思います。以下を(ローカルに)保存しますexec-from-myserver
。
#!/bin/sh
name=${0##/}
exec zsh -c "$(ssh myserver "cat 'bin/$name'")" "$0" "$@"
実行可能にして、シンボリックリンクを作成します。
ln -s exec-from-myserver mycommand
ln -s exec-from-myserver foo-bar-baz
# etc.
(注:文字列cat 'bin/whatever_name_you_chose'
は解析されたリモート側では、リテラルを含む名前は'
コードを壊したり、誤動作させたりします。特定の方法でシンボリックリンクに名前を付けると、コードインジェクションを実行することさえできます。名前を選択するのはあなたなので、それほど重要ではありません。通常の名前を使用すれば問題ありません。
ここで を呼び出すとmycommand
、ローカル スクリプトはリモート を解釈しexec
、そのコンテキストで が previous (local) の有用な値に設定されます。 を呼び出すと、リモート をプルして解釈しようとします。例:zsh
bin/mycommand
$0
$0
foo-bar-baz
bin/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.
ノート:
- 私の用語のニュアンスは次のとおりです。「リモート スクリプト」はファイルとしてリモート側に存在しますが、ローカルで解釈されます。一方、「リモート cat」は実際にはリモートにあります。
exec-from-myserver
は常に を使用するとzsh -c
、リモート スクリプト内の shebang は完全に無視されます ( を使用した実験でsource
も無視されます)。