Perché il lib / * sorgente non funziona?


11

Ho un piccolo programma che contiene la seguente struttura di cartelle:

- main.sh
- lib/
  - clean.sh
  - get.sh
  - index.sh
  - test.sh

Ogni file contiene una singola funzione in cui utilizzo main.sh.

main.sh:

source lib/*

get_products
clean_products
make_index
test_index

In quanto sopra le prime due funzioni funzionano ma le seconde due no.

Eppure se lo sostituisco source lib/*con:

source lib/get.sh
source lib/clean.sh
source lib/index.sh
source lib/test.sh

Tutto funziona come previsto.

Qualcuno sa perché source lib/*non funziona come previsto?


2
Non rispondere alla domanda, se vuoi farlo in una sola riga, guarda /etc/bashrccome usa un forciclo per gestire /etc/profile.d/*.sh. Se ritieni che il suo contenuto lib/possa essere ridotto a una riga:for i in lib/*.sh; do . "$i"; done
Rich

Risposte:


21

Il sourcebuiltin di Bash richiede solo un singolo nome file:

source filename [arguments]

Qualsiasi cosa oltre il primo parametro diventa un parametro posizionale a filename.

Un'illustrazione semplice:

$ cat myfile
echo "param1: $1"
$ source myfile foo
param1: foo

Uscita completa di help source

source: source filename [arguments]

Execute commands from a file in the current shell.

Read and execute commands from FILENAME in the current shell.  The
entries in $PATH are used to find the directory containing FILENAME.
If any ARGUMENTS are supplied, they become the positional parameters
when FILENAME is executed.

Exit Status:
Returns the status of the last command executed in FILENAME; fails if
FILENAME cannot be read.

(Ciò vale anche per l'equivalente "dot source" incorporato .che, vale la pena notare, è il modo POSIX e quindi più portatile.)

Per quanto riguarda il comportamento apparentemente contraddittorio che stai vedendo, puoi provare a eseguire main.sh dopo averlo fatto set -x. Vedere quali istruzioni vengono eseguite e quando può fornire un indizio.


7

La documentazione di Bash indica che sourcefunziona su un singolo nome file :

. (un periodo)

. nomefile [argomenti]

Leggere ed eseguire i comandi dall'argomento nomefile nel contesto della shell corrente. Se il nome file ...

E il codice sorgente ... per sorgente ... esegue il backup di questo:

result = source_file (filename, (list && list->next));

Dove source_fileè definito evalfile.cper chiamare _evalfile:

rval = _evalfile (filename, flags);

e _evalfileapre solo un singolo file:

fd = open (filename, O_RDONLY);

5

A complemento dell'utile risposta del b-layer , suggerirei di non usare mai un'espansione globosa avida se non sei sicuro che i file del tipo che stanno tentando di espandersi siano presenti.

Quando hai fatto di seguito c'è la possibilità di un file (senza .shestensione) solo un file temporaneo contenente alcuni comandi dannosi (ad esempio rm -rf *) che potrebbero essere eseguiti (supponendo che abbiano i permessi di esecuzione)

source lib/*

Quindi esegui sempre l'espansione glob con un set associato corretto, nel tuo caso, anche se potresti semplicemente eseguire il loop su *.shfile da solo

for globFile in lib/*.sh; do
    [ -f "$globFile" ] || continue
    source "$globFile"
done

Qui [ -f "$globFile" ] || continueci si occuperebbe del ritorno al di fuori del ciclo se nessun modello glob corrisponde alla cartella corrente, cioè equivalente alle opzioni di shell estese nullglobnella bashshell.


L'uso della sostituzione di processo con catavrebbe funzionato anche:source <(cat lib/*.sh)
Xophmeister,

@Xophmeister, ... per un valore più limitato per "lavoro". Se si è tentato di eseguire il debug con set -xun oggetto PS4che inserisce BASH_SOURCEe LINENOnei registri, non è più possibile vedere da quale file e linea provenga un determinato comando.
Charles Duffy,

2
@Xophmeister, ... inoltre, uno script può interromperne l'esecuzione return. Seguendo questa pratica, qualsiasi script che lo farebbe impedirebbe l'esecuzione a tutti quelli seguenti.
Charles Duffy,

1
Questo è abbastanza vicino a come viene fatto /etc/bashrcquando viene elaborato /etc/profile.d/*.sh.
Ricco

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.