1

I have a directory that contains some script files:

/scripts
    api.sh
    time.sh
    certificate.sh
    docker.sh
    nginx.sh
    wifi.sh
    ...

These scripts are not commands. They just contain some functions in them. Thus I can't add /script to the $PATH and run them. For example, api.sh has this content:

function isApi()
{
   # body
}

function resetApi() {

body

}

function testDatabase() {

body

}

I need to include them in the current session and then call their functions.

If I include them one by one using . /scripts/x.sh I can use their functions.

But when I run a loadScripts.sh bash script to load them all, it won't work:

find /scripts -mindepth 1 |
while read scriptFile;
do
    echo $scriptFile
    source $scriptFile
done

How can I include all scripts of a directory in the current session?

1 Answers1

3

Just:

for script in scripts/*.sh; do
  . "$script"
done

The . special sh builtin tells the shell to evaluate the code in the supplied file. csh has source for a similar command, some shells including bash support both . and source sometimes with slightly different semantics.

You'll also want to make sure you use . / source on loadScripts.sh. Doing ./loadScripts.sh would start a new shell to interpret the script so define those functions in that short-lived shell, not in the invoking shell.

Also make sure a / is included in the path passed to . / source, for instance by running . ./loadScripts.sh if in the current working directory, otherwise its path is or may be¹ looked up in $PATH.

Doing find... | while read...; do . ...; done is wrong, first because of all the reasons noted at Why is looping over find's output bad practice?, but also here because in several shells including bash when the lastpipe option is not enabled, the while loop would be run in a subshell, so the functions in the sourced files would only be defined in that subshell.

If you wanted to use find, but beware find doesn't sort the list of files and includes hidden files, with bash 4.4 or above, you'd do:

while IFS= read -rd '' -u3 script; do
  . "$script"
done 3< <(LC_ALL=C find scripts/ -mindepth 1 -maxdepth 1 -name '*.sh' -type f -print0)

Here adding a -type f (to restrict to files of type regular) to justify the use of find.

If using zsh instead of bash, you could just do:

for script (scripts/*(ND.)) . $script

As an equivalent (where . restricts to regular files, and D includes hidden ones).

Or:

for script (scripts/*(ND.)) emulate sh -c '. $script'

If those scripts are meant to be in sh syntax as the .sh extension suggests.


¹ bash's behaviour in that regard varies whether the posix option is enabled or not.

  • Not working. After running loadScripts.sh if I call isApi I get isApi: command not found. – Saeed Neamati Aug 07 '22 at 07:04
  • @SaeedNeamati, you'd also need to source that loadScripts.sh (with . /path/to/loadScripts.sh or . ./loadScripts.sh if in the current directory), if you intend those functions to be defined in the current shell. With just ./loadScripts.sh or bash ./loadScripts.sh the functions are only defined in the new shell that is started to interpret that script. – Stéphane Chazelas Aug 07 '22 at 07:07
  • I just copied your first code into my loadScripts.sh file and ran it ./loadScripts.sh. It does not have a function in it. It only contains your script. But I get `line 2: syntax error near unexpected token .' – Saeed Neamati Aug 07 '22 at 07:12
  • @SaeedNeamati, my bad, I forgot the do. See edit. Again, note you need . ./loadScripts.sh, not ./loadScripts.sh – Stéphane Chazelas Aug 07 '22 at 07:13
  • It worked. Thank you so much. – Saeed Neamati Aug 07 '22 at 07:17