Por que meu script Bash não reconhece aliases?

216

No meu ~/.bashrcarquivo residem duas definições:

  1. commandA, que é um alias para um caminho mais longo
  2. commandB, que é um alias para um script Bash

Quero processar o mesmo arquivo com esses dois comandos, então escrevi o seguinte script Bash:


#!/bin/bash

for file in "$@"
    do
    commandA $file
    commandB $file
done

Mesmo depois de sair da minha sessão e voltar a entrar, o Bash solicita command not founderros nos dois comandos quando executo esse script.

O que estou fazendo errado?

Zaid
fonte
10
BTW, não é necessário fazer login e logout para ter um alias reconhecido. Você precisa apenas fazer source ~/.bashrc.
tshepang
No meu caso, fui conectado pelo agente SSH remotamente, depois de adicionar o alias ao fechar o agente SSH e conectar novamente, ele começou a funcionar.
dav
Um alias é uma maneira de encurtar um comando. (Eles são usados ​​apenas em shells interativos e não em scripts - essa é uma das poucas diferenças entre um script e um shell interativo.)
Kris Roofe

Respostas:

117

Primeiro, como disse o ddeimeke, os aliases por padrão não são expandidos em shells não interativos.

Segundo, .bashrcnão é lido por shells não interativos, a menos que você defina a BASH_ENVvariável de ambiente.

Mas o mais importante: não faça isso! Por favor? Um dia você moverá esse script para algum lugar onde os aliases necessários não estejam definidos e ele será interrompido novamente.

Em vez disso, defina e use variáveis ​​de ambiente como atalhos no seu script:

#!/bin/bash

CMDA=/path/to/gizmo
CMDB=/path/to/huzzah.sh

for file in "$@"
do
    $CMDA "$file"
    $CMDB "$file"
done

fonte
5
Essa solução não funciona nos aliascasos de uso habituais . Por exemplo alias mv="mv -v --backup=numbered".
Evi1M4chine
@ Evi1M4chine: Sim, faz. Pelo menos depois de reverter a edição desnecessária de Gilles. Mas talvez seja melhor usar uma variável diferente para os parâmetros.
1
Ah, observe a falta de aspas em torno de $CMDA/ $CMDB… Além de as variáveis ​​maiúsculas serem reservadas para o bash em si, e de fato funcionar, essa falta de aspas me deixa muito desconfortável… Obrigado mesmo assim.
Evi1M4chine
@ Evi1M4chine: Uh, o que? 1. Eu mesmo removi as aspas na edição mais recente. 2. de onde você obtém o "reservado para o próprio bash"? essa seria a primeira vez que ouvi falar disso. 3. Se isso o deixa desconfortável, como você se sente ao usar o bash? De qualquer forma, use uma variável separada para as opções, como eu disse.
1
@ alvas: a suposição é que gizmonão está no caminho ou existe um comando com o mesmo nome, mas com uma prioridade mais alta. caso contrário, você pode simplesmente definir CMDAa planície gizmoem primeiro lugar.
161

Se você olhar para a página de manual do bash, encontrará:

Os aliases não são expandidos quando o shell não é interativo, a menos que a opção do shell expand_aliases seja configurada usando shopt (consulte a descrição do shopt em SHELL BUILTIN COMMANDS abaixo).

Então coloque um

shopt -s expand_aliases

no seu script.

Certifique-se de fornecer o arquivo de aliases depois de configurá-lo no seu script.

shopt -s expand_aliases
source ~/.bash_aliases
ddeimeke
fonte
7
Coloquei no meu script, mas ainda não está funcionando. Mesmo erro.
Zaid
5
Adicionar shopt -s expand_aliases source ~/.bash_aliasesfunciona perfeitamente para mim. Frequentemente, existe uma forma de detecção interativa de shell em .bashrc assim: # If not running interactively, don't do anything [ -z "$PS1" ] && return@Zaid, talvez você queira verificar isso no arquivo que você originou.
precisa
1
excelente! salvou meus scripts !! :) é tão difícil ler / pesquisar / procurar informações e páginas de manual no terminal que eu desisti há muito tempo e procurei na internet ...
Aquarius Power
2
Curiosamente, shopt -s expand_aliasesnão precisa ir antes da definição do alias, mas antes do uso do alias. Adicionando ao @FrankSchubert: A detecção interativa do shell também pode ser feita usando o $-que contém as opções para o shell, especificamente ise o shell for interativo.
válido
2
essa não é uma resposta correta ... Fornecer seus apelidos dentro do seu script não é a resposta. Você ~/.bash_aliasespode depender de outras coisas carregadas anteriormente em um shell interativo ... A coisa mais próxima que encontrei foi alterar seu hashbang para #!/bin/bash -liAinda não perfeito. Idealmente, você deve usar funções e não aliases.
Stefanos Kalantzis
44

Os aliases não podem ser exportados, portanto, não estão disponíveis em scripts de shell nos quais não estão definidos. Em outras palavras, se você os definir, eles ~/.bashrcnão estarão disponíveis your_script.sh(a menos que você forneça ~/.bashrcno script, o que eu não recomendaria, mas existem maneiras de fazer isso corretamente).

No entanto, as funções podem ser exportadas e estariam disponíveis para shell scripts que são executados em um ambiente no qual estão definidas. Isso pode ser feito colocando-o no seu bashrc:

foo ()
{
    eco "Olá, mundo!"
}
export -f foo

Como o manual do Bash diz: "Para quase todos os fins, as funções do shell são preferidas aos aliases".

Dennis Williamson
fonte
1
Enquanto isso não tecnicamente responder à pergunta, como você diz, você pode simplesmente substituir alias commandA=...com commandA() { ... }, em seguida, export commandAe você terá um comportamento idêntico ao alias. Portanto, esta é praticamente uma alternativa idêntica à aliases, tanto quanto eu sei que funciona muito bem em bash scripts
Phylliida
O problema aqui é quando você precisa de um alias ao qual passa muitas opções citadas. por exemplo, como exemplo, alias b=bashfacilita o b -c "echo test | grep test"que seria difícil de executar em funções.
Fmstrat 13/08
@Fmstrat: b () { bash "$@"; }thenb -c "echo test | grep test"
Dennis Williamson
11
[cmd line] > bash -i [your script's file path]

O ié para interativo e fornece seu bashperfil para você.

user65576
fonte
-5

Às vezes, o script bash também não reconhece a exportação. No entanto, alterá-lo para

#!/bin/sh

funciona para mim.

lwpro2
fonte
1
Não, não ...
Hafiz Temuri