Why doesn't source lib/* work?

Bash's source builtin only takes a single filename:

source filename [arguments]

Anything beyond the first parameter becomes a positional parameter to filename.

A simple illustration:

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

Full output of 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.

(This also applies to the equivalent "dot source" builtin . which, it's worth noting, is the POSIX way and thus more portable.)

As for the seemingly contradictory behavior you are seeing you can try running main.sh after doing set -x. Seeing what statements are getting executed and when may provide a clue.


Bash documentation indicates that source works on a single filename:

. (a period)

. filename [arguments]

Read and execute commands from the filename argument in the current shell context. If filename ...

And the source code ... for source ... backs this up:

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

Where source_file is defined in evalfile.c to call _evalfile:

rval = _evalfile (filename, flags);

and _evalfile only opens a single file:

fd = open (filename, O_RDONLY);

Complementing b-layer's useful answer, I would suggest never use a greedy glob expansion if you are unsure if the files of the type trying to expand are there.

When you did below there is possibility of a file (not having .sh extension) just a temporary file containing some harmful commands (e.g. rm -rf *) which could get executed (assuming they have execute permissions)

source lib/*

So always do the glob expansion with proper bound set, in your case though you could just loop on *.sh files alone

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

Here the [ -f "$globFile" ] || continue would take care of the returning out of the loop if no glob pattern matches in the current folder i.e. equivalent of the extended shell options nullglob in bash shell.

Tags:

Bash

Source