在 zsh 的源中设置 $0?

在 zsh 的源中设置 $0?

我正在尝试创建一个行为类似于“通过 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

为此,我将使用<(command),一个进程替换,它将创建一个具有类似路径的fifo /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解释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.

笔记:

  • 我的术语中的一个细微差别:“远程脚本”作为文件存在于远程端,但它在本地被解释;“远程猫”是真正远程的。
  • exec-from-myserver总是使用zsh -c,远程脚本中的shebang被完全忽略(您的实验source也忽略了它)。

相关内容