J'ai un petit programme qui contient la structure de dossiers suivante:
- main.sh
- lib/
- clean.sh
- get.sh
- index.sh
- test.sh
Chaque fichier contient une seule fonction que j'utilise dans main.sh
.
main.sh
:
source lib/*
get_products
clean_products
make_index
test_index
Dans ce qui précède, les deux premières fonctions fonctionnent mais pas les deux autres.
Pourtant, si je remplace source lib/*
par:
source lib/get.sh
source lib/clean.sh
source lib/index.sh
source lib/test.sh
Tout fonctionne comme prévu.
Quelqu'un sait pourquoi source lib/*
ne fonctionne pas comme prévu?
/etc/bashrc
comment il utilise unefor
boucle pour traiter/etc/profile.d/*.sh
. Si vous faites confiance, son contenulib/
peut être réduit à une ligne:for i in lib/*.sh; do . "$i"; done
Réponses:
La fonction
source
intégrée de Bash ne prend qu'un seul nom de fichier:Tout ce qui dépasse le premier paramètre devient un paramètre positionnel pour
filename
.Une illustration simple:
Sortie complète de
help source
(Cela s'applique également à la fonction intégrée "dot source" équivalente
.
qui, il convient de le noter, est la méthode POSIX et donc plus portable.)En ce qui concerne le comportement apparemment contradictoire que vous voyez, vous pouvez essayer d'exécuter main.sh après l'avoir fait
set -x
. Voir quelles instructions sont exécutées et quand peut fournir un indice.la source
La documentation de Bash indique que
source
fonctionne sur un seul nom de fichier :Et le code source ... pour la source ... le sauvegarde:
Où
source_file
est définievalfile.c
pour appeler_evalfile
:et
_evalfile
n'ouvre qu'un seul fichier:la source
En complément de la réponse utile de la couche b , je suggérerais de ne jamais utiliser une extension glob gourmande si vous ne savez pas si les fichiers du type essayant de se développer sont là.
Lorsque vous l'avez fait ci-dessous, il est possible qu'un fichier (sans
.sh
extension) soit juste un fichier temporaire contenant des commandes nuisibles (par exemplerm -rf *
) qui pourraient être exécutées (en supposant qu'elles disposent des autorisations d'exécution)Donc, faites toujours l'expansion glob avec un ensemble de limites approprié, dans votre cas, bien que vous puissiez simplement boucler sur des
*.sh
fichiers seulsIci, le
[ -f "$globFile" ] || continue
prendrait en charge le retour de la boucle si aucun modèle de glob ne correspond dans le dossier actuel, c'est-à-dire l'équivalent des options de shell étenduesnullglob
dansbash
shell.la source
cat
fonctionnerait également:source <(cat lib/*.sh)
set -x
etPS4
qui placeBASH_SOURCE
etLINENO
dans vos journaux, vous ne pouvez plus voir de quel fichier et de quelle ligne provient une commande donnée.return
. Suivant cette pratique, tout script faisant cela empêcherait tous les suivants de s'exécuter./etc/bashrc
lors du traitement/etc/profile.d/*.sh
.source
nécessite uniquement des autorisations de lecture, pas d'exécution