How to make a shell script execute it's commands as source commands without having to use "source scriptname.sh" expression to launch the script? Basically what I want is to type ./scriptname.sh and it's commands to act as if source was used to execute the shell-script.
3 Answers
None of the Unix shells allow you to mark a script as one that should always be sourced the way you're hoping. What I would do is create an alias
or procedure to do what you want and put it in my startup script. For example, in tcsh:
alias scriptname source \!\!
In bash, you could write it as a procedure:
scriptname( ) { source scriptname.sh $*; }
-
use
"$@"
instead of$*
-- the former is the only safe way to pass parameters that might contain whitespace. Dec 5, 2012 at 21:23
You can use a feature of bash
that allows you to intercept user input and act on it, overriding any usual command execution.
Add the following to your bash
startup script:
shopt -s extdebug
function auto_source_names {
local CMD=$BASH_COMMAND
if [[ -f "$CMD" ]] && [[ ! -x "$CMD" ]] ; then
source "$CMD"
return 1
else
return 0
fi
}
trap 'auto_source_names' DEBUG
This causes the function to be called for every command executed. If it's the name of a file that isn't executable (otherwise we'd block legitimate ./foo.sh
calls as well), it is sourced and no command executed. Be aware of files named ls
or rm
in the same directory. You could add additional safeguards, e.g. requiring .sh
file extension or file
telling you the name is a text file.
Example:
Create foo.sh
:
FOO=bar
Then:
$ echo $FOO
$ foo.sh
$ echo $FOO
bar
-
I concede it's a clever solution, but is it really advisable to, in effect, change the language default from isolating scripts in a separate process to sourcing them instead? Seems like this might break a lot of stuff. I would treat the need to source a script as the exception rather than the rule, but make it easy to type when I encounter one. Dec 5, 2012 at 18:25
-
@Daniel: This fails if the user tries to invoke the command file (script) with arguments, as in
foo.sh barrel
, because BASH_COMMAND (and consequently CMD) gets set to the entire simple command, and thus the–f
test fails. I suggest that you addeval set –– "$CMD"
and do the–f
test on$1
; thensource "$@"
. Jan 10, 2013 at 2:28 -
@Daniel: Your statement, “Be aware of files named
ls
orrm
in the same directory.” could be broadened: “Be aware that non-executable files in the current directory will totally pre-empt the normal command processing logic of the shell.” I say that because even (non-executable) files such asalias
,export
,history
,jobs
, etc…, will be sourced, ignoring and overriding their definition as builtin commands. Jan 10, 2013 at 2:30 -
@Nicole: I agree with you on two counts out of three: (1) it’s a clever solution, and (2) I believe it is inadvisable. But (3) (unless I’m overlooking or misinterpreting something) @Daniel’s solution doesn’t change the default shell behavior from isolating scripts in a separate process to sourcing them instead. Note the
[[ ! –x "$CMD" ]]
factor –– scripts that have executable mode set will fall out ofauto_source_names
with a return code of 0 (zero), telling the shell to process them normally. Jan 10, 2013 at 2:34 -
@Nicole: FYI, my concern is that this technique is too inclusive. (I heartily endorse @Daniel’s suggestion to require a
.sh
extension.) I’d be afraid of typing something likeconv.c
when I meantcc conv.c
orvi conv.c
, and having the shellsource
my C source file. (I wouldn’t really expect anything in a C source file to be a valid Unix command, but I wouldn’t want to find out the hard way, either.) Jan 10, 2013 at 2:35
The first line needs to contain the path to the interpreter:
#! /bin/bash
Then make the script file executable:
chmod +x scriptname.sh
Now you can run ./scriptname.sh
to execute it.
-
1
-
@AndreiGeorgeHondrari, it appears that most are not fammilar with your 'source shell commands' (I have years of experience with linux and never heard of such). perhaps you could explain what you want a little better. Dec 5, 2012 at 16:51
-
@Frank Thomas , bash.cyberciti.biz/guide/Source_command . See what Nicole Hamilton answered. That's the solution. Dec 5, 2012 at 16:53
-
thank you, that was very informative. from the article you linked, you can include a 'source' statement in the driver script just below the shebang, and then call the driver script withput specifing 'source'. Do you have a driver script, or are you just trying to call a function in a source script file directly from the CLI? Dec 5, 2012 at 17:04
-
@Frank When you run a script the usual way as a command, the shell forks a copy of itself as a new process to run the script. That isolates whatever that script does from the copy of the shell you're using interactively. If the script changes the environment variables or current directory, all of that's lost when the script exits. It doesn't change the state of the copy of the shell you're interacting with. The
source
statement causes the script to be run without forking to create that isolation. All the commands in the script are run by your copy of the shell and can change its state. Dec 5, 2012 at 18:00
. file
is equivalent tosource file
Actually,source
is a "bashism" (Bash specific) and the dot operator is "standard" (POSIX).source
command is originally from Bill Joy's csh.