On linux systems, it is good practice to prefix shell scripts by a commentary giving the path to the requiered shell to execute.
example:
#!/bin/bash
#or
#!/usr/bin/env bash
This makes the shell syntax awaited explicit (and it is a final touch telling people the script has been reviewed).
But I'm currently writing scripts on iSeries (AS400) where I use qsh.
And I don't know if there is something similar to write on top of my scripts.
Do you know the path to the interpretor? What do you write in your scripts?
I use:
#!/bin/qsh
In PASE (call qp2term) you can use
#!/bin/sh
Related
I've a master shell script which calls functions defined in various other shell scripts. The master script includes other scripts using 'source' command.
I want to use a common interpreter for all the scripts regardless of what the she bang ("#!/bin/sh") has been set to in those scripts. I want to supply that interpreter from command line.
for example:
master.sh (with #!/bin/sh)
subscript1.sh (with #!/bin/sh)
subscript2.sh (with #!/bin/sh)
subscript3.sh (with #!/bin/sh)
master.sh calls functions which are defined in the subscripts and are included as 'source subscript1.sh', 'source subscript2.sh' and 'source subscript3.sh'.
When I run ./master.sh, the subscript use their respective interpreters as directed by "#!/bin/sh" line. I want to run all of them using '/bin/bash', the master and the subscripts but without changing the she bang line because there are a lot of such scripts. Is there any way to do this?
Call the interpreter explicitly:
bash ./master.sh
Note that the shebang line has no effect on scripts run using source. That command always executes the script in the current shell process, so it uses whatever interpreter is currently running.
But this all seems dangerous. If someone writes #!/bin/sh instead of #!/bin/bash, it may have dependencies on sh syntax that would be violated if bash were used instead.
I have a shell script on a mac (OSX 10.9) named msii810161816_TMP_CMD with the following content.
matlab
When I execute it, I get
./msii810161816_TMP_CMD: line 1: matlab: command not found
However, when I type matlab into the shell directly it starts as normal. How can it be that the same command works inside the shell but not inside a shell script? I copy-pasted the command directly from the script into the shell and it worked ...
PS: When I replace the content of the script with
echo matlab
I get the desired result, so I can definitely execute the shell script (I use ./msii810161816_TMP_CMD)
Thanks guys!
By default, aliases are not expanded in non-interactive shells, which is what shell scripts are. Aliases are intended to be used by a person at the keyboard as a typing aid.
If your goal is to not have to type the full path to matlab, instead of creating an alias you should modify your $PATH. Add /Applications/MATLAB_R2014a.app/bin to your $PATH environment variable and then both you and your shell scripts will be able to simply say
matlab
This is because, as commenters have stated, the PATH variable inside of the shell executing the script does not include the directory containing the matlab executable.
When a command name is used, like "matlab", your shell looks at every directory in the PATH in order, searching for one containing an executable file with the name "matlab".
Without going into too much detail, the PATH is determined by the shell being invoked.
When you execute bash, it combines a global setting for basic directories that must be in the PATH with any settings in your ~/.bashrc which alter the PATH.
Most likely, you are not running your script in a shell where the PATH includes matlab's directory.
To verify this, you can take the following steps:
Run which matlab. This will show you the path to the matlab executable.
Run echo "$PATH". This will show you your current PATH settings. Note that the directory from which matlab is included in the colon-separated list.
Add a line to the beginning of your script that does echo "$PATH". Note that the directory from which matlab is not included.
To resolve this, ensure that your script is executed in a shell that has the needed directory in the PATH.
You can do this a few ways, but the two most highly recommended ones would be
Add a shebang line to the start of your script. Assuming that you want to run it with bash, do #!/bin/bash or whatever the path to your bash interpreter is.
The shebang line is not actually fully standardized by POSIX, so BSD-derived systems like OSX will happily handle multiple arguments to the shebanged executable, while Linux systems pass at most one argument.
In spite of this, the shebang is an easy and simple way to document what should be used to execute the script, so it's a good solution.
Explicitly invoke your script with a shell as its interpreter, as in bash myscript.sh or tcsh myscript.sh or even sh myscript.sh
This is not incompatible with using a shebang line, and using both is a common practice.
I believe that the default shell on OSX is always bash, so you should start by trying with that.
If these instructions don't help, then you'll have to dig deeper to find out why or how the PATH is being altered between the calling context and the script's internal context.
Ultimately, this is almost certainly the source of your issue.
Let's say a script is called with /bin/sh. Is it possible to source another script from that script and to have it be interpreted with #!/bin/bash?
It would appear that the #!/bin/bash doesn't do anything...
And by source, at this point I am meaning the functionality of manipulating the parent environment.
No. The whole point of sourcing a script is that the script is interpreted by the shell doing the sourcing. If, as is often the case, /bin/sh is bash, then you will get the desired behavior. Otherwise, you are out of luck.
Try the source command, or dot operator. You might also try the env command. Note, make sure you export if you're using source (or dot).
I am new to TCL scripting and shell scripting. I want to invoke a TCL script from the shell script. I have tried as below.
#!/bin/sh
for i in {1..5}
do
my_script
test_script
done
If I run the script, it is throwing error as follows,
./sample.sh: line 5: my_script: command not found
./sample.sh: line 5: test_script: command not found
Can anyone help me out with this ?
Thanks in advance.
If they cannot be found in your $PATH you have to provide a path to your scripts, e.g.:
./my_myscript # current directory
/path/to/test_script # absolute path
If you haven't made your script executable (with chmod +x) then you need to use:
tclsh my_script.tcl
Or maybe tclsh8.5 /path/to/script.tcl or many variations on that.
If you have made the script executable, check that the directory containing the script is on your PATH (if not, use the full filename of the script or adjust your PATH) and that you've got a suitable #! line. The usual recommended one is:
#!/usr/bin/env tclsh8.5
as that will search your path for the tclsh8.5 executable instead of hard-coding it.
From man tclsh. I guess the second block answers your question.
If you create a Tcl script in a file whose first line is
#!/usr/local/bin/tclsh
then you can invoke the script file directly from your shell if you mark the file as executable. [...]
An even better approach is to start your script files with the following three lines:
#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" ${1+"$#"}
This approach has three advantages over the approach in the previous paragraph [...]
You should note that it is also common practice to install tclsh with its version number as part of the name.This has the advantage of allowing multiple
versions of Tcl to exist on the same system at once, but also the disadvantage of making it harder to write scripts that start up uniformly across different versions of Tcl.
I have a number of scripts which need to specify the python binary which runs them:
#! /home/nargle/python/bin/python2.6
I need to adapt these scripts to work at two different sites. Lots of tools are installed in different places, so at new site 2 the script needs to start with:
#! /user/nargle/python/bin/python2.6
..
I want to replace directly-quoted paths with environment variables which are set differently for each site. What I would like is for this to work:
#! $MY_PYTHON_PATH
but it doesn't! I am slightly hazy on where to research this. Is it the executing shell (be it bash, csh or whatever) which detects the '#!' at the start of a script (be it bash, python or whatever) and fires up the interpreter/shell to run it?
I feel that there must be some way to do this. Please advise!
Oh yes, there is one more constraint: we cannot use the path for this. This may seem like a stupid restriction but this is for a large environment with many users
The environment is RHEL 5.7.
EDIT It has been suggested to use a shell script and that is the current plan: it works fine:
$MY_PYTHON_PATH some_script file.py $#
The problem is really that we have lots of people using the python files, and lots of automated tests which need to changed. If it has to be done it has to be done but I if possible I want to minimise the impact of a change of working practice for scores of people.
EDIT It would also be possible to have a link in a location which is the same on both systems, and which links to the real binary in a different target on each system. This is quite feasible but seems kind of messy: we use the linux 'modules' package to setup environment variables for many tools and it would be nice if we could take the python path from our modulefiles.
EDIT It isn't the answer but this feels like the kind of evil hack I was looking for:
http://docs.nscl.msu.edu/daq/bluebook/html/x3237.html
.. see "Example 4-2. #! lines for bash and for tclsh"
EDIT I hoped this might work but it didn't:
!# /usr/bin/env PATH=$PATH:$MY_PYTHON_PATH python2.6
The common solution is to change the shebang to
#!/usr/bin/env python2.6
Then, just arrange your $PATH to point to the right python2.6 on each machine.
Write a wrapper shell script. If you have script.py, write a script.py.sh with the following content:
#!/bin/bash
PYTHON_SCRIPT=$( echo "$0" | sed -e 's/\.sh$//' )
exec $MY_PYTHON_PATH $PYTHON_SCRIPT "$#"
Disclaimer: This isn't tested, just wrote it off the top of my head.
Now just set up your MY_PYTHON_PATH on each machine, and call script.py.sh instead of script.py.
Summary This solution is only second-best, since it requires a lot of script calls to be changed from script.py to script.py.sh, something that should be avoided if at all possible.
Alternative
Use env to call a python-finder script, which just calls the python binary contained in $MY_PYTHON_PATH. The python-finder script has to be in the same location on both machines, use symlinks if necessary.
#!/usr/bin/env /usr/local/bin/python-finder.sh
The contents of python-finder.sh:
#!/bin/bash
exec $MY_PYTHON_PATH "$#"
This works because for interpreter scripts (those starting with a shebang) execve calls the interpreter and passes the filename to env, which in turn passes it on to the command it calls.
I was being silly: using variable expansion with env does work.
#! /usr/bin/env PATH="$PATH:$MY_PYTHON_PATH" python2.6
We can do:
#!/bin/bash
"exec" "python" "$0"
print "Hello World"
from http://rosettacode.org/wiki/Multiline_shebang#Python