![Установка $0 в исходном коде zsh?](https://rvso.com/image/1586953/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0%20%240%20%D0%B2%20%D0%B8%D1%81%D1%85%D0%BE%D0%B4%D0%BD%D0%BE%D0%BC%20%D0%BA%D0%BE%D0%B4%D0%B5%20zsh%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
Для этого я буду использовать <(command)
, подстановку процесса, которая создаст fifo с путем вроде /proc/self/fd/<n>
, перенаправит command
в него stdout , и выполнит оценку по этому пути. fifo=<(echo 'hi!'); echo $fifo; cat $fifo
выведет echo /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
, шебанг в удаленном скрипте полностью игнорируется (ваш эксперимент сsource
также проигнорировал его).