В Bash, что означает каждый фрагмент «$ {BASH_SOURCE: - $ {(%): -% x}}» - PullRequest
1 голос
/ 21 марта 2020

Недавно я хотел узнать, как лучше всего найти путь к текущему скрипту / файлу в Bash.

Я нашел много ответов. В частности, один из них был:

"${BASH_SOURCE:-${(%):-%x}}"

Я помню, как в то время решал, что это лучшее решение для моих нужд. Теперь я пытаюсь вспомнить почему. Я знаю, что значат некоторые из произведений, но не все. И даже с тем, что я знаю, я не могу собрать все вместе, чтобы понять это. Оно работает. Но почему?

Все усилия, которые я предпринял, чтобы найти этот конкретный c код в Интернете (включая поиск его фрагментов), потерпели неудачу, поэтому я не могу найти, где я нашел его изначально.

Может кто-нибудь сказать мне, что означает каждая часть (и, возможно, даже предложить, почему я выбрал это вместо других ответов)?

Спасибо!


ОБНОВЛЕНИЕ на следующий день : отличный ответ (и комментарии) от @rici, который объясняет все, включая то, почему я выбрал его.

Кажется, я выбрал все это выражение, чтобы обеспечить возможность надежного использования исходных файлов, в которых я его использую, в обоих случаях. bash и zsh - что было и есть цель. При двойных подстановках все выражение получает одинаковый ответ в любой оболочке.

Объясняет, почему я не смог понять (или найти что-нибудь разумное через google для) $ {(%): -% x} часть в bash, потому что ... ну ... это не имеет большого смысла в bash, смеется, потому что это для zsh. По этой причине я сейчас добавляю к этому тег zsh.


Второе ОБНОВЛЕНИЕ через час, на случай, если это кому-нибудь поможет: теперь я нашел следующее:

$ {BASH_SOURCE [0]} эквивалент в zsh?

... вот откуда я получил ${(%):-%x} от оригинала, в частности, этот конкретный c ответ:

{ ссылка }

Ответы [ 2 ]

5 голосов
/ 21 марта 2020

Это своеобразное выражение пытается выдать один и тот же результат в bash и в zsh: пути к файлу выполняемого в данный момент сценария.

В bash,

"${BASH_SOURCE:-${(%):-%x}}"

означает «$BASH_SOURCE, если оно существует и не является пустым, а в противном случае ${(%):-%x}». Пока вы используете это в контексте, в котором $BASH_SOURCE определено как непустое значение, в противном случае недопустимая подстановка ${(%):-%x} никогда не будет использоваться и bash не будет жаловаться на это. [Примечание 1]

Подробное объяснение $BASH_SOURCE см. В этом превосходном ответе от @ mklement0.

Теперь в zsh переменная $BASH_SOURCE обычно не определяется (хотя я полагаю, что это может быть экспортировано из родительского), поэтому замена происходит, и zsh затем заменяет ее расширением ${(%):-%x}. Bash пользователи могут найти это еще более загадочным, но мы можем разобрать его следующим образом:

  1. ${...:-...} означает то же самое, что и в bash: используйте правую руку часть, если левая часть пуста или не определена. В отличие от bash, zsh позволяет левой части быть полностью пустой, а не только переменной, значение которой пусто. Таким образом, {:-foo} - сложный способ записи foo.

  2. ${(flags)...} заставляет заданные флаги оцениваться при расширении. В этом случае у нас есть флаг %, что означает, что «быстрое расширение» должно быть выполнено для расширения параметра. [Примечание 2]

  3. Без обработки флагов у нас остается {:-%x}; как указано в пункте 1, это эквивалентно строке %x. Но флаг (%) вызывает быстрое расширение %x. И в zsh расширении подсказки, %x - это - ждать его - имя исполняемого файла сценария.

Короче говоря, в zsh, ${(%):-%x} означает (почти) то же самое, что $BASH_SOURCE делает в bash. И поэтому ${BASH_SOURCE:-${(%):-%x}} расширяется до текущего исходного файла сценария в bash и zsh.


Примечания

  1. Если $BASH_SOURCE равно неопределенное или пустое, с другой стороны, это приведет к «плохой замене». Как мы увидим через мгновение, ${(flags)...} является синтаксисом zsh -specifi c, но не поэтому bash жалуется на это. Для bash это выглядит как удаление суффикса (оператор %) несуществующего параметра $(. И он жалуется, потому что $( не является допустимым именем параметра.

    Для сравнения рассмотрим очень похожую, но действительную замену ${#%):-%x}. Это имеет то же значение, что и $#, потому что $# не заканчивается ):-%x. Этот синтаксический анализ может быть удивительным для человеческого глаза, но bash видит его простым как день.

  2. Zsh, как и bash, имеет чрезвычайно настраиваемые подсказки, использующие специальные escape-последовательности в одном переменных подсказок. (Переменными стандартного приглашения Posix являются $PS1, $PS2 и $PS4; оба bash и zsh предлагают несколько других.) Bash предлагает некоторые специальные backsla sh последовательности (\u - это, например, текущее имя пользователя), а также позволяет интерпретировать произвольные расширения параметров при расширении приглашения. Zsh также имеет множество escape-последовательностей , но использует % в качестве escape-символа (%n - текущее имя пользователя) и позволяет расширения параметров, если установлена ​​опция оболочки prompt_subst.

    Обратите внимание, что обычно вы не можете поэкспериментировать с подсказками zsh, просто установив $PS1, как вы можете в bash, потому что большинство zsh установок используют «темы подсказок». После включения тем подсказок вам необходимо создать собственную тему, чтобы изменить строки подсказок, поскольку настройки тем автоматически применяются перед каждой командой.

1 голос
/ 21 марта 2020

${parameter:-word} расширяется до word, если parameter не установлено. Например:

$ unset a b
$ c=123
$ echo ${a:-${b:-$c}}
123

Здесь и a, и b не установлены, поэтому c расширяется. Расширение параметра ${(%):-%x} дает ошибку bad substitution. Это связано с тем, что $( не является допустимым параметром. Bash manual определяет параметр как:

Параметр - это объект, который хранит значения. Это может быть имя, число или один из специальных символов, перечисленных ниже. Переменная - это параметр, обозначаемый именем. Переменная имеет значение и ноль или более атрибутов. Атрибуты присваиваются с помощью команды встроенного объявления (см. Описание встроенного объявления в Bash Встроенные функции).

и name as:

name: «слово», состоящее только из букв, цифр и подчеркиваний, и начинающееся с буквы или подчеркивать. «Имена используются как имена переменных и функций оболочки. Также называется «идентификатором».

...