Скрипт запускается при выполнении, но не работает при получении - PullRequest
0 голосов
/ 19 июня 2020

Оригинальное название: Непрямая подстановка параметров прерывается при получении скрипта (zsh)

zsh 5.7.1 (x86_64-apple-darwin19.0)

GNU bash, версия 4.4.20 (1) -release (x86_64-p c - linux -gnu)

Я разрабатываю сценарий оболочки на Ma c и я пытаюсь сохранить его переносимостью между bash и zsh, поэтому следует учитывать индексацию массива. Я знаю, что могу установить KSH_ARRAYS, чтобы индексирование начиналось с 0, но я решил запросить ОС для используемой оболочки и соответственно установить начальный индекс, что привело к описанной ниже проблеме.

Это имело смысл (по крайней мере, для меня!) использовать непрямое расширение, что и привело к проблеме. Рассмотрим сценарий косвенно. sh:

#! /bin/bash

declare -r ARRAY_START_BASH=0
declare -r ARRAY_START_ZSH=1

declare -r SHELL_BASH=0
declare -r SHELL_ZSH=1

# Indirect expansion is used to reference the values of the variables declared
# in this case statement e.g. ${!ARRAY_START}
case $(basename $SHELL) in
  "bash" )
    declare -r SHELL_ID=SHELL_BASH
    declare -r ARRAY_START=ARRAY_START_BASH
    ;;

  "zsh" )
    declare -r SHELL_ID=SHELL_ZSH
    declare -r ARRAY_START=ARRAY_START_ZSH
    ;;

  * )
    return 1
    ;;

esac

echo "Shell ID: ${!SHELL_ID} Index arrays from: ${!ARRAY_START}"

Он отлично работает при запуске из командной строки, находясь в том же каталоге:

<my home> ~ % echo "$(./indirect.sh)"
Shell ID: 1 Index arrays from: 1

Проблемы возникают, когда я использую сценарий:

<my home> ~ % echo "$(. ~/indirect.sh)"
/Users/<me>/indirect.sh:28: bad substitution

Я не понимаю, почему выбор источника скрипта изменяет поведение расширения параметра.

Это ожидаемое поведение? Если так, я был бы признателен, если бы кто-нибудь мог это объяснить и, надеюсь, предложить обходной путь.

Ответы [ 2 ]

1 голос
/ 21 июня 2020

Чтобы добавить к вашему ответу (то, что я собираюсь сказать, слишком длинное для комментария), я не могу придумать какое-либо приложение, почему ваш скрипт может быть полезен, если не получен. На самом деле, я сам столкнулся с необходимостью в таком скрипте ровно в одном случае:

Поскольку я использую в качестве интерактивной оболочки не только zsh, но также иногда bash, я написал свой .zshr c и .bashr c для настройки всего (включая определение переменных и функций оболочки для интерактивного использования). Для безопасной работы я пытаюсь поместить код, работающий как под bash, так и под zsh, в один файл (скажем: .commonr c), а мои .zshr c и .bashr c имеют внутри них

source .commonrc

Хотя многие вещи в bash и zsh настолько разные, что я не могу поместить их в .commonr c, некоторые могут, при условии, что я немного поправлю. Одна из причин головной боли - это, очевидно, различная индексация массивов, которую вы, похоже, пытаетесь решить. Так что у меня тоже есть похожая функция. Однако мне не нужна конструкция ca case для этого. Вместо этого мой .bashr c выглядит так (с использованием вашего наименования переменных):

...
declare -r ARRAY_START=0
source .commonrc
...

и мой .zshr c выглядит так:

...
declare -r ARRAY_START=1
source .commonrc
...

Поскольку не бывает, что .bashr c запускается из zsh, и наоборот, мне не нужно спрашивать, какая у меня оболочка.

1 голос
/ 20 июня 2020

Проблема, описанная в исходном посте, не имеет ничего общего с косвенным расширением. Различие в поведении является результатом вызова разных оболочек в зависимости от того, «выполняется» или «из источника» скрипта. Эти различия обнаруживают основной недостаток c при получении оболочки из переменной $ SHELL, лежащей в основе дизайна скрипта. Если оболочка, определенная в $ SHELL, не соответствует shebang, сценарий завершится ошибкой либо при запуске, либо при выполнении. Далее следует объяснение.

Косвенное расширение не предлагает ценности в данном сценарии, потому что значения могут быть также легко присвоены напрямую. Они должны быть назначены таким образом независимо от синтаксиса, используемого для косвенного расширения между оболочками. На самом деле, другие различия синтаксиса между оболочками делают все предпосылки для обнаружения спорной оболочки! Однако, если оставить это в стороне, различие в поведении является результатом вызова разных оболочек в зависимости от того, «выполняется» или «из источника» скрипта. Поведение источника хорошо документировано с многочисленными объяснениями в Интернете, но для контекста вот как это работает:

Выполнение сценария Используйте синтаксис «./» для выполнения сценарий. При таком запуске скрипт выполняется в суб-оболочке. Любые изменения, которые скрипт вносит в свою оболочку, применяются к подоболочке, а не к оболочке, в которой был запущен скрипт, поэтому эти изменения теряются при выходе из оболочки, потому что подоболочка, в которой он выполняется, также уничтожается. Например, если сценарий изменяет рабочий каталог, это происходит во вспомогательной оболочке. Рабочий каталог основной оболочки, запустившей сценарий, не изменяется после завершения сценария. Если вы хотите внести изменения в оболочку, в которой был запущен сценарий, он должен иметь источник.

Источник сценария Используйте синтаксис «источник» для создания сценария. При запуске таким образом сценарий по сути становится аргументом исходной команды, которая обрабатывает вызов соответствующего выполнения. В некоторых оболочках (например, k sh) используется одна точка «.» вместо «source».

Когда сценарий выполняется с синтаксисом «./», shebang в верхней части файла используется для определения того, какую оболочку использовать. При получении сценария shebang игнорируется, и вместо него используется оболочка, в которой запускается сценарий. Также обратите внимание, что точка, которая появляется в синтаксисе команды «./», используемой для выполнения сценария, не связана с периодом, который иногда используется в качестве псевдонима для исходной команды.

В сценарии в сообщении используется bash в операторе shebang, поэтому он работает при выполнении, потому что запускается с использованием bash. Когда он получен из zsh, он обнаруживает неправильный синтаксис косвенного раскрытия:

“${!A_VAR}"

Правильный синтаксис:

"${(P)A_VAR}"

Однако исправление синтаксиса не поможет, потому что это затем завершится ошибкой при выполнении. Shebang вызовет bash, и синтаксис снова будет неправильным. Это делает косвенный доступ бесполезным для доступа к переменной, предназначенной для обозначения используемой оболочки. Что еще более важно, дизайн, основанный на запросе переменной среды для оболочки, ошибочен из-за различий в оболочке, которая в конечном итоге используется в зависимости от того, выполняется сценарий или источник.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...