Escopo de alias em funções bash

8

Eu uso um script (ao qual não tenho acesso de gravação) que cria vários aliases para configurar um ambiente. Eu gostaria de criar uma função bash para configurar meu ambiente, mas parece que os aliases não sobrevivem ao corpo da função.

Veja um exemplo mínimo:

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

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

.

Agora, se eu simplesmente pesquisar aliases.sh interativamente, as coisas funcionam como esperado:

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

No entanto, se eu chamar a função definida no meu .bashrc, ele não reconhecerá o alias depois de obter sua definição:

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

O que está acontecendo aqui? Existe algo que estou faltando sobre o escopo do comando alias quando usado em uma função?

Editar: adicionarei alguns detalhes além do exemplo mínimo para esclarecer o que estou tentando realizar.

No meu trabalho, desenvolvo e executo muitos softwares em um cluster e / ou grade. Eu tenho vários projetos que exigem ambientes completamente diferentes, como diferentes versões do gcc, lançamentos de software específicos, PATHs de configuração e dados e várias variáveis de ambiente. Os administradores fornecem os scripts para configurar várias coisas, geralmente definindo funções de shell ou aliases, que invocam outras funções ou aliases ou executam vários scripts. Para mim, é uma caixa preta.

Gostaria de configurar meus próprios vários ambientes com um único comando. Atualmente, faço algo como:

[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

Esses comandos geralmente precisam ser executados em ordem. Minha ideia basicamente era apenas copiar as linhas acima em um bloco de funções, mas, como mostra o exemplo original, isso simplesmente não funciona. Soluções alternativas alternativas são mais que bem-vindas!

    
por chase 29.01.2014 / 02:45

2 respostas

8

Uma solução alternativa é colar esses comandos em um arquivo de texto em vez de um bloco de função. Algo como:

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

Guarde isso como setup1.sh de onde quiser. O truque é então fornecer este arquivo, não executá-lo:

$ source setup1.sh

Isso executará os aliases que estão no script e também os disponibilizará ao seu shell atual.

Você pode simplificar ainda mais o processo adicionando isso ao seu .bashrc :

alias setupLotsOfThings="source setup1.sh"

Agora você pode simplesmente executar setupLotsOfThings e obter o comportamento desejado da função.

Explicação

Existem dois problemas aqui. Primeiro, os aliases não estão disponíveis para a função em que são declarados, mas apenas quando essa função é encerrada e segundo, quando os aliases não estão disponíveis nos scripts. Ambos são explicados na mesma seção de man bash :

Aliases are not expanded when the shell is not interactive, unless the expand_aliases shell option is set using shopt (see the description of shopt under SHELL BUILTIN COMMANDS below).

The rules concerning the definition and use of aliases are somewhat confusing. Bash always reads at least one complete line of input before executing any of the commands on that line. Aliases are expanded when a command is read, not when it is executed. Therefore, an alias definition appearing on the same line as another command does not take effect until the next line of input is read. The commands following the alias definition on that line are not affected by the new alias. This behavior is also an issue when functions are executed. Aliases are expanded when a function definition is read, not when the function is executed, because a function definition is itself a compound command. As a consequence, aliases defined in a function are not
available until after that function is executed.
To be safe, always put alias definitions on a separate line, and do not use alias in com‐ pound commands.

Depois, há a diferença entre executar e terceirizar um arquivo. Basicamente, a execução de um script faz com que ele seja executado em um shell separado, enquanto o sourcing faz com que ele seja executado no shell atual. Portanto, o fornecimento de setup.sh torna os aliases disponíveis para o shell pai durante a execução como um script não faria.

    
por 29.01.2014 / 04:33
7

Na verdade, seus aliases estão disponíveis depois que a função é carregada! Você pode usá-los no seu shell interativo ou no seu .bashrc depois de executar a função.

A restrição é que os aliases em uma definição de função são expandidos quando a definição da função é lida, não quando a função é avaliada. Esta é uma limitação do bash. Então, isso vai funcionar:

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

Mas não é isso:

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

Se você precisar de aliases que possam ser usados dentro de funções e possam ser definidos depois que a função for analisada, faça-os funcionar. Lembre-se de que você pode usar o command builtin para invocar um comando externo de uma função com o mesmo nome.

    
por 29.01.2014 / 23:55

Tags