environment variable expansion in first line of shell script - bash

My ruby shell scripts specify the ruby interpreter in the first line of the script as:
#!/Users/me/.rvm/rubies/ruby-1.9.3-p194/bin/ruby
The problem is that when I upgrade to a new ruby version, I have to edit all the script files to update the interpreter. There is an environment variable available, $MY_RUBY_HOME, that expands to the current path (minus the /bin/ruby part). However, all my attempts to use:
#!{$MY_RUBY_HOME}/bin/ruby
#!${MY_RUBY_HOME}/bin/ruby
etc
fail ("bad interpreter: No such file or directory"). I suspect environment expansion isn't done on the first line, so I may just be out of luck. I would be interested if anybody has been able to use environment variable expansion on the program definition line in a shell script.

Put ${MY_RUBY_HOME}/bin in your $PATH and use #!/usr/bin/env ruby. See here.

Related

What is the practical value of using a shebang line?

I don't notice any difference when I call a script with say source or ruby. I'm guessing the benefit of a shebang line is that the environment knows what program to invoke if you're running the script as an executable. Not sure if this is the case; but I'm just verifying.
The source command ignores the shebang line. When a script is invoked by shell in the normal way (not with . or source), shell uses the shebang line to fork the right interpreter for the script. The shebang line can contain:
direct path to any executable that can interpret the script, along with arguments to the interpreter (#!/usr/local/bin/perl -w)
/usr/bin/env that would find the path (#!/usr/bin/env bash). The advantage of this is that it prevents the hardcoded path and lets the shell pick up the environment specific path. In this case, there is no way to send an argument to the interpreter
See also:
Should I use a Shebang with Bash scripts?
How does the #! shebang work?
Does the shebang determine the shell which runs the script? - Unix & Linux Stack Exchange
Why does Python in Linux require the line #!/usr/bin/python? - AskUbuntu

UNIX/solaris shell script shebang in include file

I have a functions.sh script with a bunch of global functions that i want to use in other scripts. this functions script is written in bash (#!/bin/bash)
Those many scripts had been written over the years, so the older ones or with the #!/bin/sh (which is different from #!/bin/bash in solaris).
My question here is, when you call the functions.sh file (with . /path/to/functions.sh) from within a sh (not bash) script, is the shebang line of "functions.sh" interpreted ?
In a nutshell, can you call a bash written function script from another shell-type script (with proper shebang lines in both) ?
Thanks !
As long as you want to use the function you need to source the scripts and not execute it
source /path/to/functions.sh
or as per the POSIX standards, do
. ./path/to/functions.sh
from within the sh script, which is equivalent to including the contents of function.sh in the file at the point where the command is run.
You need to understand the difference between sourcing and executing a script.
Sourcing runs the script from the parent-shell in which the script is
invoked; all the environment variables, functions are retained until the
parent-shell is terminated (the terminal is closed, or the variables
are reset or unset),
Execute forks a new shell from the parent shell and those variables,functions
including your export variables are retained only in the sub-shell's
environment and destroyed at the end of script termination.
When you source a file, the shebang in that file is ignored (it is not on the first line since it is included in the caller script and is seen as comment).
When you include an old script with #!/bin/sh it will be handled as the shell of the caller. Most things written in /bin/sh will work in bash.
When you are running a sh or ksh script and you include (source) a bash file, all bash specific code will give problems.

is it possible to have an environment variable in the "env" line of a shell script?

we have a requirement to have a script where the env is ruby (in a custom location) but setting the #!/usr/bin/env , where script contains a variable e.g.
#!/usr/bin/env ${NEWROOT}/location/of/ruby/bin/ruby
The calling script has set NEWROOT, and if I replace NEWROOT with the actual content e.g.
#!/usr/bin/env /home/user/location/of/ruby/bin/ruby
it works!
does anyone know why?
Parameter substitution is performed by the shell, not by the kernel. The shebang line will remain unsubstituted even as the kernel invokes env with the argument.

How can I store and execute the command "export PATH=$PREFIX/bin" from a script?

I would like to write a script that has several commands of the kind
> export PATH=$PREFIX/bin
Where
> $PREFIX = /home/usr
or something else. Instead of typing it into the the Shell (/bin/bash) I would run the script to execute the commands.
Tried it with sh and then with a .py script having the line,
> commands.getstatusoutput('export PATH=$PREFIX/bin')
but these result into the error "bad variable name".
Would be thankful for some ideas!
If you need to adjust PATH (or any other environment variable) via a script after your .profile and equivalents have been run, you need to 'dot' or 'source' the file containing the script:
. file_setting_path
source file_setting_path
The . notation applies to all Bourne shell derivatives, and is standardized by POSIX. The source notation is used in C shell and has infected Bash completely unnecessarily.
Note that the file (file_setting_path) can be specified as a pathname, or if it lives in a directory listed on $PATH, it will be found. It only needs to be readable; it does not have to be executable.
The way the dot command works is that it reads the named file as part of the current shell environment, rather than executing it in a sub-shell like a normal script would be executed. Normally, the sub-shell sets its environment happily, but that doesn't affect the calling script.
The bad variable name is probably just a complaint that $PREFIX is undefined.
Usually a setting of PATH would look something like
export PATH=$PATH:/new/path/to/programs
so that you retain the old PATH but add something onto the end.
You are best off putting such things in your .bashrc so that they get run every time you log in.

"Command not found" inside shell script

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.

Resources