8

Я использую сценарий (к которому у меня нет прав записи), который создает несколько псевдонимов для настройки среды. Я хотел бы создать функцию bash для настройки моей среды, но кажется, что псевдонимы не сохраняются в теле функции.

Вот минимальный пример:

# aliases.sh
alias fooAlias='echo "this will never work!"'  

,

# .bashrc
function setupLotsOfThings() {
    source aliases.sh
    fooAlias
}

,

Теперь, если я просто использую aliases.sh интерактивном режиме, все будет работать как положено:

[mycomputer]~/ $ source aliases.sh
[mycomputer]~/ $ fooAlias
this will never work!

Однако, если я вместо этого вызову функцию, определенную в моем .bashrc, он не распознает псевдоним после получения его определения:

[mycomputer]~/ $ setupLotsOfThings
-bash: fooAlias: command not found

Что здесь происходит? Что-то мне не хватает в области действия команды alias при использовании в функции?

Изменить: я добавлю некоторые детали помимо минимального примера, чтобы пролить свет на то, что я пытаюсь достичь.

Для своей работы я разрабатываю и запускаю много программного обеспечения в кластере и / или сетке. У меня есть несколько проектов, которые требуют совершенно разных сред, таких как разные версии gcc, определенные выпуски программного обеспечения, конфигурации и переменные данных и различные переменные среды. Администраторы предоставляют сценарии для настройки различных вещей, обычно путем определения функций оболочки или псевдонимов, которые вызывают другие функции или псевдонимы или запускают различные сценарии. Для меня это черный ящик.

Я хотел бы настроить свои собственные различные среды с помощью одной команды. В настоящее время я делаю что-то вроде:

[mycomputer]~/ $ source /some/environment/setup/script.sh
[mycomputer]~/ $ aliasToSetupSomeSoftwareVersion    #this was defined in the above
[mycomputer]~/ $ anotherAliasForOtherSoftware
[mycomputer]~/ $ source /maybe/theres/another/script.sh
[mycomputer]~/ $ runSomeOtherSetup      # this was defined in the new script

Эти команды обычно должны выполняться по порядку. Моя идея в основном заключалась в том, чтобы просто скопировать вышеупомянутые строки в функциональный блок, но, как показывает оригинальный пример, это просто не работает. Альтернативные обходные пути приветствуются!

2 ответа2

8

Альтернативное решение - вставить эти команды в текстовый файл вместо функционального блока. Что-то вроде:

## This is needed to make the sourced aliases available
## within the script.
shopt -s expand_aliases

source /some/environment/setup/script.sh
aliasToSetupSomeSoftwareVersion
anotherAliasForOtherSoftware
source /maybe/theres/another/script.sh
runSomeOtherSetup

Сохраните это как setup1.sh где угодно. Хитрость заключается в том, чтобы сделать его источником этого файла, а не выполнить его:

$ source setup1.sh

Это запустит псевдонимы, которые есть в скрипте, а также сделает их доступными для вашей текущей оболочки.

Вы можете еще больше упростить процесс, добавив это в ваш .bashrc:

alias setupLotsOfThings="source setup1.sh"

Теперь вы можете просто запустить setupLotsOfThings и получить желаемое поведение от функции.


объяснение

Здесь есть два вопроса. Во-первых, псевдонимы недоступны для функции, в которой они объявлены, но только после выхода из этой функции, а во-вторых, псевдонимы недоступны в сценариях. Оба объяснены в одном и том же разделе man bash:

Псевдонимы не раскрываются, когда оболочка не является интерактивной, если только параметр оболочки expand_aliases не установлен с помощью shopt (см. Описание shopt в разделе «Команды SHELL BUILTIN» ниже).

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

Тогда есть разница между выполнением и поиском файла. По сути, при запуске скрипта он запускается в отдельной оболочке, а источник - в текущей оболочке. Таким образом, sourcing setup.sh делает псевдонимы доступными для родительской оболочки, в то время как выполнение скрипта не будет.

7

На самом деле, ваши псевдонимы доступны после загрузки функции! Вы можете использовать их в вашей интерактивной оболочке или в вашем .bashrc после выполнения функции.

Ограничение состоит в том, что псевдонимы в определении функции раскрываются при чтении определения функции, а не при оценке функции. Это ограничение bash. Так что это будет работать:

function setupLotsOfThings() {
    source aliases.sh
}
setupLotsOfThings
fooAlias

Но не это:

function setupLotsOfThings() {
    source aliases.sh
}
function useTheAliases() {
    fooAlias
}
setupLotsOfThings
useTheAliases

Если вам нужны псевдонимы, которые можно использовать внутри функций и которые можно определить после анализа функции, вместо этого сделайте их функциями. Помните, что вы можете использовать встроенную command для вызова внешней команды из функции с тем же именем.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .