在 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在其上下文中設定為 previous (local) 的有用值$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也忽略了它)。

相關內容