Eu tenho um pequeno programa que contém a seguinte estrutura de pastas:
- main.sh
- lib/
- clean.sh
- get.sh
- index.sh
- test.sh
Cada arquivo contém uma única função na qual eu uso main.sh
.
main.sh
:
source lib/*
get_products
clean_products
make_index
test_index
Acima, as duas primeiras funções funcionam, mas as duas seguintes não.
No entanto, se eu substituir source lib/*
por:
source lib/get.sh
source lib/clean.sh
source lib/index.sh
source lib/test.sh
Tudo funciona como esperado.
Alguém sabe por source lib/*
que não funciona como o esperado?
/etc/bashrc
como ele usa umfor
loop para lidar/etc/profile.d/*.sh
. Se você confia no conteúdo,lib/
ele pode ser reduzido a uma linha:for i in lib/*.sh; do . "$i"; done
Respostas:
O Bash
source
embutido usa apenas um único nome de arquivo:Qualquer coisa além do primeiro parâmetro se torna um parâmetro posicional para
filename
.Uma ilustração simples:
Saída total de
help source
(Isso também se aplica à "fonte de pontos" equivalente embutida
.
que, vale a pena notar, é a maneira POSIX e, portanto, mais portátil.)Quanto ao comportamento aparentemente contraditório que você está vendo, pode tentar executar o main.sh depois de fazer
set -x
. Ver quais instruções estão sendo executadas e quando pode fornecer uma pista.fonte
A documentação do Bash indica que
source
funciona em um único nome de arquivo :E o código fonte ... para fonte ... confirma isso:
Onde
source_file
está definidoevalfile.c
para chamar_evalfile
:e
_evalfile
abre apenas um único arquivo:fonte
Complementando a resposta útil da b-layer , eu sugeriria nunca usar uma expansão gananciosa da glob se você não tiver certeza se os arquivos do tipo que estão tentando expandir estão lá.
Quando você fez abaixo, existe a possibilidade de um arquivo (sem
.sh
extensão) apenas um arquivo temporário contendo alguns comandos prejudiciais (por exemplorm -rf *
) que podem ser executados (assumindo que eles tenham permissões de execução)Sempre faça a expansão glob com o conjunto de limites adequado, no seu caso, embora você possa fazer um loop apenas nos
*.sh
arquivosAqui,
[ -f "$globFile" ] || continue
ele cuidaria do retorno do loop se nenhum padrão glob corresponder na pasta atual, ou seja, equivalente às opções estendidas do shellnullglob
nobash
shell.fonte
cat
também funcionaria:source <(cat lib/*.sh)
set -x
e umPS4
que colocaBASH_SOURCE
eLINENO
em seus logs, não era mais possível ver de qual arquivo e linha um determinado comando vem.return
. Após essa prática, qualquer script que faça isso impediria a execução de todos os seguintes./etc/bashrc
quando é processado/etc/profile.d/*.sh
.source
requer apenas permissões de leitura, não executar