LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 11-21-2008, 11:10 AM   #1
Jessard
Member
 
Registered: Jun 2005
Location: Boston, USA
Distribution: Gentoo, CentOS
Posts: 82

Rep: Reputation: 16
Detect bash script source vs. direct execution


Is there an easy way to tell, from within a bash script, if that script is being executed as part of a source command as opposed to being executed directly? I have a script that I'd like to have provide a set of functions if sourced, but actually call one of its functions if run directly.

I've gotten used to doing this sort of thing with the Python __name__ == "__main__" and Ruby __FILE__ == $0 idioms, and started writing this script accordingly before realizing I didn't even know if that made sense. (And of course, googling with "source" in the search term really doesn't give me what I'm looking for )
 
Old 11-21-2008, 11:16 AM   #2
pixellany
LQ Veteran
 
Registered: Nov 2005
Location: Annapolis, MD
Distribution: Arch/XFCE
Posts: 17,802

Rep: Reputation: 741Reputation: 741Reputation: 741Reputation: 741Reputation: 741Reputation: 741Reputation: 741
If I understand sourcing correctly, the code to be sourced is simply "pasted" into the host script before running. It's hard to see how the sourced code could know this was happening.

I am not a programmer, but my guess is that you want to call things like this as subroutines so you can pass arguments.
 
Old 11-21-2008, 11:59 AM   #3
burschik
Member
 
Registered: Jul 2008
Posts: 159

Rep: Reputation: 31
$0 might offer an answer.
 
Old 11-21-2008, 12:01 PM   #4
colucix
LQ Guru
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,509

Rep: Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981
Quote:
Originally Posted by burschik View Post
$0 might offer an answer.
Maybe, but what if the script is sourced from another script?
 
Old 11-21-2008, 01:57 PM   #5
jan61
Member
 
Registered: Jun 2008
Posts: 235

Rep: Reputation: 47
Moin,

I think, the "$0" idea is good:
Code:
jan@jack:~/tmp> cat source.sh
function is_subshell() {
  test "`basename $1`" = "source.sh" && return 1
  return 0
}

function my_function() {
  echo my_function
}

is_subshell $0 && my_function
jan@jack:~/tmp> cat src_parent.sh
echo -n "sourcing ... "
. ./source.sh
echo
echo -n "calling from bash ... "
bash ./source.sh
echo
echo -n "calling directly ... "
./source.sh
echo

jan@jack:~/tmp> ./src_parent.sh
sourcing ... my_function

calling from bash ...
calling directly ...
Jan
 
Old 11-21-2008, 02:06 PM   #6
pixellany
LQ Veteran
 
Registered: Nov 2005
Location: Annapolis, MD
Distribution: Arch/XFCE
Posts: 17,802

Rep: Reputation: 741Reputation: 741Reputation: 741Reputation: 741Reputation: 741Reputation: 741Reputation: 741
Quote:
Originally Posted by burschik View Post
$0 might offer an answer.
How?

from the BASH manual:
Code:
0
    Expands to the name of the shell or shell script. This is set at shell initialization. If Bash is invoked with a file of commands (see Shell Scripts), $0 is set to the name of that file. If Bash is started with the -c option (see Invoking Bash), then $0 is set to the first argument after the string to be executed, if one is present. Otherwise, it is set to the filename used to invoke Bash, as given by argument zero.
If a function is sourced and not called, where does one find the relevant value for $0?
 
Old 11-22-2008, 01:36 PM   #7
jlinkels
LQ Guru
 
Registered: Oct 2003
Location: Bonaire, Leeuwarden
Distribution: Debian /Jessie/Stretch/Sid, Linux Mint DE
Posts: 5,194

Rep: Reputation: 1040Reputation: 1040Reputation: 1040Reputation: 1040Reputation: 1040Reputation: 1040Reputation: 1040Reputation: 1040
contens of file weg:
Code:
jlinkels@jlinkels_pc:/tmp$ cat weg
echo $0
called from the command line:
Code:
jlinkels@jlinkels_pc:/tmp$ ./weg
./weg
sourced:
Code:
jlinkels@jlinkels_pc:/tmp$ . ./weg
-bash
jlinkels
 
Old 11-23-2008, 10:57 AM   #8
Jessard
Member
 
Registered: Jun 2005
Location: Boston, USA
Distribution: Gentoo, CentOS
Posts: 82

Original Poster
Rep: Reputation: 16
OK, thanks burschik. Its behavior is a little complicated, but it looks like it can work.

Quote:
Originally Posted by pixellany View Post
If a function is sourced and not called, where does one find the relevant value for $0?
Apparently from the environment it is being "sourced into". I tried out a few situations (thanks, Jan, for the examples)... From the shell itself, I get "-bash". If I source a file that echos $0, it also says "-bash". If I execute that file using bash (either with the shebang or with "bash filename" (the two should be the same, right?)) it gets set to the filename. All of that seems to match the behavior you quoted from the manual, which makes sense to me.

So, if I understand right, the value of $0 will "cascade" through sourced files, and will always show the most recent file that was executed with bash. If there isn't one, it will stay at "-bash". It looks like the only tricky part is figuring out if your particular file is being executed or sourced, as opposed to any file having been executed in the "chain". (Jan's example deals with this by checking against the expected file name.)

Thanks everybody, this has been very informative
 
Old 11-23-2008, 01:15 PM   #9
radoulov
Member
 
Registered: Apr 2007
Location: Milano, Italia/Варна, България
Distribution: Ubuntu, Open SUSE
Posts: 212

Rep: Reputation: 37
You could also check the BASH_SOURCE array (only bash >= 3):

Code:
$ ./s
$0 is ./s
$BASH_SOURCE is ./s
$ . s
$0 is bash
$BASH_SOURCE is ./s
$ cat s
#! /bin/bash

printf '$0 is %s\n$BASH_SOURCE is %s\n' "$0" "$BASH_SOURCE"
Something like this (I don't know if it will cover all the cases that you are interested in):

Code:
$ cat s
#! /bin/bash

[[ $BASH_SOURCE != $0 ]] && printf '%s running sourced ...\n' "$BASH_SOURCE"

$ bash s
$ ./s
$ . s
./s running sourced ...
$ source s
./s running sourced ...
For example exec s will be silent ...

Last edited by radoulov; 11-23-2008 at 01:26 PM.
 
Old 11-24-2008, 10:13 AM   #10
Jessard
Member
 
Registered: Jun 2005
Location: Boston, USA
Distribution: Gentoo, CentOS
Posts: 82

Original Poster
Rep: Reputation: 16
Ah, beautiful! That's exactly what I've been looking for.

Now I can do:

Python:
Code:
if __name__ == "__main__":
    main()
Ruby:
Code:
if __FILE__ == $0
  main
end

Bash:
Code:
if [[ "$BASH_SOURCE" == "$0" ]]
then
    main
fi
Thanks!
 
1 members found this post helpful.
Old 07-16-2009, 10:04 PM   #11
Kamilion
LQ Newbie
 
Registered: Dec 2003
Posts: 2

Rep: Reputation: 0
Here's a neat snippit:

infokernel.sh
Code:
#!/bin/bash -x
my_info()
{
  #empty line
  #empty line
  echo "${LINENO} Script Ran: ${0}"
  #empty line
  echo "${LINENO} Sourced subscript is:" `basename ${BASH_SOURCE}`
  #empty line
  echo "${LINENO} ${FUNCNAME} now executing with params ${@}"
}
infohusk.sh
Code:
#!/bin/bash -x
echo "${LINENO} Hi There!"
. ${PWD}/infokernel.sh
echo "${LINENO} Sourced!"
my_info Param1 Param2
echo "${LINENO} Goodbye!"
Results in the output (for me)

Code:
+ echo '2 Hi There!'
2 Hi There!
+ . /home/kamilion/workspace/filetasker/home/infokernel.sh
+ echo '4 Sourced!'
4 Sourced!
+ my_info Param1 Param2
+ echo '6 Script Ran: ./infohusk.sh'
6 Script Ran: ./infohusk.sh
++ basename /home/kamilion/workspace/filetasker/home/infokernel.sh
+ echo '8 Sourced subscript is:' infokernel.sh
8 Sourced subscript is: infokernel.sh
+ echo '10 my_info now executing with params Param1' Param2
10 my_info now executing with params Param1 Param2
+ echo '6 Goodbye!'
6 Goodbye!
 Param1 Param2
Or direct output without -x:

Code:
2 Hi There!
4 Sourced!
6 Script Ran: ./infohusk.sh
8 Sourced subscript is: infokernel.sh
10 my_info now executing with params Param1 Param2
6 Goodbye!
Need bash 3.x+ for this!
 
Old 11-30-2010, 07:43 AM   #12
kschafer2598
LQ Newbie
 
Registered: Nov 2010
Posts: 1

Rep: Reputation: 0
I ran into this problem myself recently. I realized the simplest way to determine if a script was sourced, was to pass it a parameter telling it that it was sourced. I have verified that the snippets below do work.

-----
Script #1
#!/bin/bash
test_func(){
whoami
pwd
}

#If sourced, do something
if [[ $1 = sourced ]]; then
echo "I was sourced!"
return 0
fi

#Call script #2
./script_2

Script #2
#!/bin/bash

#Call script #1, with a sourced parameter
. script_1 sourced
test_func
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
making the parent direct child processes to pause/sleep and resume execution expeliarmus Programming 1 08-14-2007 06:11 AM
Bash script to detect hardware jimigoon Programming 4 06-30-2007 10:22 AM
BASH: open console on script execution Quis Programming 2 02-07-2006 10:41 AM
Bash Script to Detect USB drive mount status nutthick Programming 6 02-02-2005 09:17 AM
bash script to detect scsi address at boot ewto Programming 2 10-20-2003 03:47 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 01:06 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration