Tengo un pequeño programa que contiene la siguiente estructura de carpetas:
- main.sh
- lib/
- clean.sh
- get.sh
- index.sh
- test.sh
Cada archivo contiene una sola función que uso en main.sh
.
main.sh
:
source lib/*
get_products
clean_products
make_index
test_index
En lo anterior las dos primeras funciones funcionan pero las dos últimas no.
Sin embargo, si lo reemplazo source lib/*
con:
source lib/get.sh
source lib/clean.sh
source lib/index.sh
source lib/test.sh
Todo funciona como se esperaba.
Alguien sabe por qué source lib/*
no funciona como se esperaba?
/etc/bashrc
cómo utiliza unfor
bucle para tratar/etc/profile.d/*.sh
. Si confía en el contenidolib/
, puede reducirse a una frase:for i in lib/*.sh; do . "$i"; done
Respuestas:
El
source
código incorporado de Bash solo toma un único nombre de archivo:Cualquier cosa más allá del primer parámetro se convierte en un parámetro posicional para
filename
.Una simple ilustración:
Salida completa de
help source
(Esto también se aplica a la "fuente de puntos" incorporada equivalente
.
que, vale la pena señalar, es la forma POSIX y, por lo tanto, más portátil).En cuanto al comportamiento aparentemente contradictorio que está viendo, puede intentar ejecutar main.sh después de hacerlo
set -x
. Ver qué declaraciones se ejecutan y cuándo pueden proporcionar una pista.fuente
La documentación de Bash indica que
source
funciona en un solo nombre de archivo :Y el código fuente ... para fuente ... respalda esto:
Donde
source_file
se define enevalfile.c
llamar_evalfile
:y
_evalfile
solo abre un solo archivo:fuente
Complementando la útil respuesta de b-layer , sugeriría que nunca use una expansión codiciosa global si no está seguro de si los archivos del tipo que intenta expandirse están allí.
Cuando lo hizo a continuación, existe la posibilidad de que un archivo (que no tenga
.sh
extensión) sea solo un archivo temporal que contenga algunos comandos dañinos (por ejemplorm -rf *
) que podrían ejecutarse (suponiendo que tengan permisos de ejecución)Por lo tanto, siempre realice la expansión global con el conjunto enlazado adecuado, en su caso, aunque solo podría recorrer los
*.sh
archivos soloAquí
[ -f "$globFile" ] || continue
se encargaría de regresar del bucle si no coincide el patrón global en la carpeta actual, es decir, el equivalente de las opciones de shell extendidasnullglob
enbash
shell.fuente
cat
también funcionaría:source <(cat lib/*.sh)
set -x
y unPS4
que poneBASH_SOURCE
yLINENO
en sus registros, ya no podría ver de qué archivo y línea proviene un comando dado.return
. Siguiendo esa práctica, cualquier script que haga eso evitaría que todos los siguientes se ejecuten./etc/bashrc
cuando se procesa/etc/profile.d/*.sh
.source
solo requiere permisos de lectura, no ejecución