Псевдонім, який визначає функції баша


9

Я використовую сценарій (до якого у мене немає доступу для запису), який створює купу псевдонімів, щоб створити середовище. Я хотів би створити функцію 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, специфічні версії програмного забезпечення, PATH з конфігурацією та даними, а також різні змінні середовища. Адміністратори надають скриптам для налаштування різних речей, як правило, шляхом визначення функцій оболонки або псевдонімів, які викликають інші функції чи псевдоніми або виконують різні сценарії. Для мене це чорна скринька.

Я хотів би налаштувати свої власні різні середовища однією командою. В даний час я роблю щось на кшталт:

[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

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

Відповіді:


10

Альтернативне рішення - вставити ці команди в текстовий файл замість функціонального блоку. Щось на зразок:

## 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:

Псевдоніми не розгортаються, коли оболонка не є інтерактивною, якщо не встановлено параметр shell_aliases оболонки за допомогою shopt (див. Опис прострілу в SHELL BUILTIN COMMANDS нижче).

Правила щодо визначення та використання псевдонімів дещо заплутані. Bash завжди читає щонайменше один повний рядок введення, перш ніж виконувати будь-яку команду в цьому рядку. Псевдоніми розгортаються, коли команда читається, а не коли вона виконується. Отже, визначення псевдоніму, що з’являється в тому ж рядку, що й інша команда, не набирає чинності, поки не буде прочитаний наступний рядок введення. Команди, що відповідають визначенню псевдоніму в цьому рядку, не впливають на новий псевдонім. Така поведінка також є проблемою, коли виконуються функції. Псевдоніми розширюються при зчитуванні визначення функції, а не при виконанні функції, оскільки визначення функції саме по собі є складною командою. Як наслідок, псевдоніми, визначені у функції,
недоступні до того моменту, як ця функція буде виконана.
Щоб бути безпечним, завжди кладіть визначення псевдоніму в окремий рядок і не використовуйте псевдоніми в командах comound.

Тоді існує різниця між виконанням та розміщенням файлу. В основному, запуск сценарію змушує його запускатись в окремій оболонці, а джерело - при запуску в поточній оболонці. Отже, джерело setup.shнадає псевдоніми доступними для батьківської оболонки, виконуючи її як сценарій, не було б.


Ну, я працюю над кластером і маю декілька таких "псевдонімних" сценаріїв, які допомагають налаштувати програмне середовище тощо. Скрипт псевдоніму визначає багато різних псевдонімів; моя мета - викликати конкретне середовище шляхом отримання правильних псевдонімів, а потім запуску (деяких) цих псевдонімів. Я вважаю за краще робити це в одній команді, ніж доводиться виконувати кілька команд послідовно.
переслідуйте

І PS сценарій, який встановлює псевдоніми, на жаль, дуже багатослівний і трохи повільний (оскільки він торкається багатьох файлів на NFS), тому я вважаю за краще не надсилати всі ці речі, наприклад, під час входу.
переслідувати

@chase, але вони запускаються лише під час запуску setupLotsOfThings, вони просто недоступні для самої функції. Вони працюють над оболонкою, з якої ви назвали функцію. У будь-якому разі, якщо ваша функція лише джерела псевдонімів, чому б не просто використовувати псевдонім? Наприклад: alias setupstuff="source aliases.sh".
тердон

правильно, але я не переживаю за сферу застосування як такої . В ідеалі я просто хочу поєднати "вихідний матеріал" і "запустити псевдоніми" в один. Можливо, це можна зробити за допомогою 3 функцій? функція sourceStuff () {source ...}; функція runStuff () {someAlias; ...}; налаштування функціїLotsOfThings () {sourceStuff; runStuff; };
погоню

@chase Так, я подумав про це, але це не вийшло :). Чи можете ви розширити своє запитання ще деяким з того, що вам потрібно зробити? Функції можуть справлятися лише з такою складністю, можливо, вам доведеться написати трохи сценарій.
тердон

7

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

Обмеження полягає в тому, що псевдоніми у визначенні функції розширюються при зчитуванні визначення функції, а не тоді, коли функція оцінюється. Це обмеження баш. Так це спрацює:

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

Але не це:

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

Якщо вам потрібні псевдоніми, які можна використовувати всередині функцій і які можна визначити після розбору функції, замість них зробіть їх функціями. Пам'ятайте, що ви можете використовувати commandвбудований для виклику зовнішньої команди з однойменної функції.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.