LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   global bash shell functions (https://www.linuxquestions.org/questions/programming-9/global-bash-shell-functions-831851/)

Jerry Mcguire 09-13-2010 04:18 AM

global bash shell functions
 
Hi, I wonder if there is anyway to make a user-defined bash shell function global, meaning the function can be use in any bash shell scripts, interactively or not.

This is what I attempted:

Code:

$ tail -n 3 /etc/bashrc
echotm () {
  echo "[`date`] $@"
}

$ echotm hello world
[Mon Sep 13 17:15:28 HKT 2010] hello world

$ cat a.sh
#!/bin/sh
echotm hello world

$ sh a.sh
a.sh: line 2: echotm: command not found

Any idea?

ghostdog74 09-13-2010 04:28 AM

you can source it. man source for more

Jerry Mcguire 09-13-2010 04:34 AM

That works! Thanks.

Jerry Mcguire 09-13-2010 05:24 AM

wait wait...
There is an undesired side-effect of sourcing the file.

As you can see, the command 'echotm' displays timestamp when echo'ing. It is widely used in writing logs in my systems. However, as a habit whether good or bad, I have an 'exit' statement in all the scripts. The exit statement down in some sub-script (script called by another) terminates the entire script in the first level, rendering the whole thing broken.

Code:

$ cat lv1.sh
#!/bin/sh
echo lv 1 in
sh lv2.sh
echo lv 1 out
exit 0

$ cat lv2.sh
#!/bin/sh
echo lv 2 in
echo lv 2 out
exit 0

$ sh lv1.sh
lv 1 in
lv 2 in
lv 2 out
lv 1 out

$ source lv1.sh
lv 1 in
lv 2 in
lv 2 out

Of course, replacing 'echo' with 'echotm' won't work in the first case. But then, rear part of lv1.sh is never executed in the second case.

My last resort is to make 'echotm' a executable shell script file in /usr/local/bin.

vikas027 09-13-2010 06:11 AM

You can also use alias for this purpose

Code:

alias echotm='echo hello world';export echotm
To make this permanent include it in your /etc/bashrc or $HOME/.bashrc

druuna 09-13-2010 06:11 AM

Hi,

Sourcing is done in the current shell, executing is done in a new child shell.

Sourcing a script that you would normally execute can have side effects (exit being one of those).

If you put your function in, for example .bashrc or .bash_profile it will be accessible in all the (bash) shells and its sub-shells.

I have, for example, this function in my .bashrc:
Code:

ALL2LOWER ()
{
    /bin/ls * | awk '{ print "mv "$0" "tolower($0) }' | bash
}

It is accessible from the shell and from within scripts.

You can also make a dedicated file that you can source that holds all the functions you need, there shouldn't be a hash-bang or exit in that file. You can decide to source this file by hand when you need it or source this file from for example .bashrc so that all the functions are accessible in all shells.

Hope this helps.

konsolebox 09-13-2010 10:08 AM

Quote:

Originally Posted by Jerry Mcguire (Post 4095906)
Code:

$ cat lv1.sh
#!/bin/sh
echo lv 1 in
sh lv2.sh
echo lv 1 out
exit 0

$ cat lv2.sh
#!/bin/sh
echo lv 2 in
echo lv 2 out
exit 0

$ sh lv1.sh
lv 1 in
lv 2 in
lv 2 out
lv 1 out

$ source lv1.sh
lv 1 in
lv 2 in
lv 2 out


The output's quite odd. Before you called 'source lv1.sh', did you also replaced 'sh lv2.sh' in lv1.sh with 'source lv2.sh' ?

Anyway, the solution I think would be to just call the subscript inside a subshell:

a.sh
Code:

#!/bin/sh

echofunc() {
    echo "echofunc: $1"
}

echofunc "a 0"
( . ./b.sh; )
echofunc "a 1"

exit 0

b.sh
Code:

#!/bin/sh

echofunc "b 0"
( . ./c.sh; )
echofunc "b 1"

exit 0

c.sh
Code:

#!/bin/sh

echofunc "c 0"
echofunc "c 1"

exit 0

sh a.sh

---- EDIT ----

You might also want to try Shell Script Loader.

You can use the call() function for that.

David the H. 09-13-2010 10:49 AM

Functions can also be exported in the same way variables can (at least in bash). Just use the -f flag.

export -f functionname

This will make it available to any script run within that shell.

Overall though, I think it's best simply to incorporate everything directly into your script in some way. The more external dependencies you have, the more difficult it will be to keep track of it all in the long run.

Jerry Mcguire 09-13-2010 09:37 PM

Quote:

Originally Posted by konsolebox (Post 4096104)
The output's quite odd. Before you called 'source lv1.sh', did you also replaced 'sh lv2.sh' in lv1.sh with 'source lv2.sh' ?

Yes, you are right. Should be 'source lv2.sh' in lv1.sh.

--
Alias won't be a nice option because it has limitations such as, only the front part is converted. Alias can't do things like 'ls -l $@ | less'.

--
Also, I did put the function echotm in my .bashrc or /etc/bashrc, and export -f echotm. It works.

And then putting common functions in a separate file without hash-bang and exit seem to be working very well too.

Thank you all.

konsolebox 09-13-2010 11:16 PM

Quote:

Originally Posted by David the H. (Post 4096150)
Functions can also be exported in the same way variables can (at least in bash). Just use the -f flag.

export -f functionname

This will make it available to any script run within that shell.

Only that he needed something that will resolve with the exit builtin. Also, the return builtin might have also been a better alternative (wrapped inside a function).
Quote:

Overall though, I think it's best simply to incorporate everything directly into your script in some way. The more external dependencies you have, the more difficult it will be to keep track of it all in the long run.
Well there may still be some coders that will instead prefer not to place all codes in one script.. especially when the size of the code is large. Dependencies may be made less of a problem if you leave them independent and stable. It may also be easy to track them if they are organized, and that the names and codes are written.. uniformly.

I somehow remember something similar with this conversation. It was quite an odd event of the past :).

konsolebox 09-13-2010 11:27 PM

Quote:

Originally Posted by Jerry Mcguire (Post 4096622)
Yes, you are right. Should be 'source lv2.sh' in lv1.sh.

Huh? What I meant is if you did as the output implies that.. you did. So with your answer, does it mean that you didn't?

Quote:

Also, I did put the function echotm in my .bashrc or /etc/bashrc, and export -f echotm. It works.

And then putting common functions in a separate file without hash-bang and exit seem to be working very well too.

Thank you all.
I'm curious of the oddity but nevermind. Good thing your problem's already solved.

Jerry Mcguire 09-14-2010 02:36 AM

I did the lv1-lv2-test one machine, and then re-type the output in LQ on another machine, which is why.

----

why odd?

Method 1:

~/.bashrc:
Code:

# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

# User specific aliases and functions
echo2 () {
        echo hello world
}
export -f echo2

a.sh:
Code:

#!/bin/sh
echo2
exit 0

execution:
Code:

$ sh a.sh
hello world

Method 2:

~/common_func:
Code:

echo3 () {
        echo good day
}

b.sh:
Code:

#!/bin/sh
source $HOME/common_func
echo3
exit 0

execution:
Code:

$ sh b.sh
good day



All times are GMT -5. The time now is 03:45 AM.