19

I have defined a bash function in my ~/.bashrc file. This allows me to use it in shell terminals. However, it does not seem to exist when I call it from within a script.

How can I define a bash function to be used by scripts as well?

3

3 Answers 3

13

~/.bash_profile and ~/.bashrc are not read by scripts, and functions are not exported by default. To do so, you can use export -f like so:

$ cat > script << 'EOF'
#!/bin/bash
foo
EOF
$ chmod a+x script
$ ./script
./script: line 2: foo: command not found
$ foo() { echo "works" ; } 
$ export -f foo
$ ./script
works

export -f foo could also be called in ~/.bash_profile to make this function available to scripts after login. Be warned that export -f is not portable.

A better solution would be to source the file containing the function using . file. This is much more portable, and doesn't rely on your environment being set up in a particular way.

4
  • why not just declare a function like function myFunction { ... } in ~/.bash_profile and you're good to go?
    – amphibient
    Commented Feb 4, 2013 at 16:34
  • If I understood properly your answer (regarding sourcing a file with the function), this would mean that I have to source the file explicitly in every script, which is pretty much annoying. This is not much less complicated than just copy-pasting the function itself in every script. I would save some lines, sure, but that's all. However, the export solution seems to work properly. Thanks.
    – Pythonist
    Commented Feb 4, 2013 at 16:53
  • @foampile, this is precisely what I did and does not work when calling the function from a script.
    – Pythonist
    Commented Feb 4, 2013 at 16:56
  • 1
    @Onturenio : the second method @chris-down proposed is indeed better: 1) When someone read the script, they are aware that it needs some foo function from some file 2) You can better control the content of that file than make sure that the invoking shell didn't change foo before invoking your script. You could add safety checks on file to make sure it's untampered, for example. (not easy, but possible). (well, you could also do those checks on the defined foo function... but you get my drift ^^ I think the method 2 is cleaner.) 3) file will only contain what's needed, not more. Commented Feb 4, 2013 at 17:25
9

.bashrc is only read by interactive shells. (Actually, that's an oversimplification: bash is quirky in this respect. Bash doesn't read .bashrc if it's a login shell, interactive or not. And there's an exception even to the exception: if bash's parent process is rshd or sshd, then bash does read .bashrc, whether it's interactive or not.)

Put your function definitions in a file in a known place, and use the . (also spelled source) builtin to include that file in a script.

$ cat ~/lib/bash/my_functions.bash
foo () {
…
$ cat ~/bin/myscript
#!/bin/bash
. ~/lib/bash/my_functions.bash
foo bar

If you want, you can follow ksh's autoload feature. Put each function definition in a file with the same name as the function. List the directories containing the function definitions in the FPATH variable (a colon-separated list of directories). Here's a crude approximation of ksh's autoload which actually loads the function immediately instead of on-demand:

autoload () {
  set -- "$(set +f; IFS=:;
            for d in $FPATH; do
              if [ -r "$d/$1" ]; then echo -E "$d/$1"; break; fi;
            done)"
  [[ -n $1 ]] && . "$1"
}
1
  • +1 for autoload, although I recommend using the ones that come with bash. The latest one supports lazy load.
    – Starfish
    Commented Jan 29, 2015 at 5:30
1

Do you need a function? If not, consider pulling out the logic into a separate, stand-alone Bash script in your $PATH. For example, I had this in my ~/.bashrc:

# echo public IP address
alias wanip='dig +short myip.opendns.com @resolver1.opendns.com'

~/bin is in my $PATH, so I created ~/bin/wanip with the following contents:

#!/bin/bash

# echo public IP address
dig +short myip.opendns.com @resolver1.opendns.com

And ran chmod 0755 ~/bin/wanip to make it executable. Now I can execute wanip from other scripts.

I like having wanip in a stand-alone Bash script. It reminds me that I want this logic generally available (besides just in my current interactive Bash session). The script nicely encapsulates the logic and documentation for same.

This site is temporarily in read-only mode and not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .