This question already has answers here:
Should I use a Shebang with Bash scripts?
(8 answers)
Closed 8 years ago.
Suppose you have a bash script B, that you are sourcing from another bash script A. B has a bunch of variable and function definitions. A is the main driver script. Do you need the #!/bin/bash line on top of both A and B? What happens if you do and if you don't?
The shebang is only mandatory for those scripts, which shall be executed by the operating system in the same way as binary executables. If you source in another script, then the shebang is ignored.
On the other hand. IF a script is supposed to be sourced, then it is convention to NOT put any shebang at the start.
The shebang is used if you run the script directly as an executable file (for example with the command ./script.sh). In this case it tells the operating system which executable to run.
It's not required and has no effect if you for example write bash ./script.sh or source the script.
You should use shebang in all scripts especially those using any non-sh compatible features.
In Debian for example, default shell is dash (not bash). If you use bash-only feature and don't specify that this script should be interpreted by bash it may fail even on linux. It will fail on Solaris or HP-UX almost for sure.
If your file is to be only sources by other script, then you can omit shebang line but do not set executable permission. Also for such files is good to keep /bin/sh compatibility.
I strongly recommend to read DashAsBinSh.
Related
This question already has answers here:
How can I check if a program exists from a Bash script?
(39 answers)
Closed 6 years ago.
I've read in some bash FAQ a while ago (that I don't remember), that which should be avoided and command -v preferred.
Why is that so? What are the advantages, disadvantages of either one?
Well...
command is likely built in to your shell, and with the -v option will tell you how your shell will invoke the command specified as its option.
which is an external binary, located at /usr/bin/which which steps through the $PATH environment variable and checks for the existence of a file.
A reason to select the former over the latter is that it avoids a dependency on something that is outside your shell.
The two commands do different things, and you should select the one that more closely matches your needs. For example, if command is built in to your shell, command -v command will indicate this with its output (through the non-existence of path), but which command will try to point to a file on your path, regardless of how command would be interpreted by your shell.
This question already has answers here:
Global environment variables in a shell script
(7 answers)
Closed 5 years ago.
I'm working a small project which needs using OpenMPI to make "mpicc" work.
I made a file make_cmd:
#!/bin/bash
module load OpenMPI
However, after executing ./make_cmd, I was told:
mpicc: command not found
But if I just type on the command line: module load OpenMPI, then mpicc is working.
Why is that? Thanks!
See this answer on neighbouring site.
Because module is an alias/shell function and not a binary program, it's not necessarily available in the non-interactive sub-shell that is created when you run your script. You could probably run source make_cmd though, as that will just run the commands in your current interactive shell. You could ditch the #!/bin/bash line in that case.
This question already has answers here:
Brace expansion with variable? [duplicate]
(6 answers)
Closed 5 years ago.
How do I expand a brace expansion that originally come from a string variables ? Note that the string variable is a requirement.
#!/usr/bin/env bash
TEXT_DIRS='opt/*/{doc,gtk-doc}'
My intention is reading a bash source from zsh, or maybe other language as well such as Perl or Python. Get the configuration from /etc/makepkg.conf, as below.
DOC_DIRS=(usr/{,local/}{,share/}{doc,gtk-doc} opt/*/{doc,gtk-doc})
It is all, for just, learning purpose.
Is that possible, to expand from string ?
The tricky thing here is that once Bash resolves the environment variable, it doesn't make another pass to process its contents again. You'd have to evaluate the content of the variable in another pass of the shell ( eg another shell command).
Here's one way to do that:
bash-4.4# TEXT_DIRS='/usr/*/{bin,src,lib}'
bash-4.4# bash -c ls\ $TEXT_DIRS
ls: /usr/*/src: No such file or directory
/usr/local/bin:
/usr/local/lib:
Here, I'm dynamically generating a shell command that I then evaluate to handle the 2nd expansion. (I took the liberty of changing the paths to something that would match on typical systems, so make sure to change it back if you try to test).
Dynamically generating code is always dangerous, if you can't trust the input. That's essentially how command injection attacks work. But use of eval in your own shell with trusted input is more or less "safe", though I rarely find myself using it unless in a contrived scenario like yours, or some of my own worse ideas.
This question already has answers here:
unix command line execute with . (dot) vs. without
(5 answers)
Closed 7 years ago.
In UNIX, when you want to run a shell script located in pwd, you do:
./somescript.sh
But there is also:
. somescript.sh
What does the second command do?
The dot is an alias for the command "source": http://ss64.com/bash/source.html.
The main difference is that the first syntax tries to execute the script by running some interpreter for it (as determined by the hashbang magic header value). For a shell file, the interpreter is usually bash or sh, and so your shell will launch a new shell process as a subprocess and pass the script as a parameter. The script will run isolated in this subprocess. If it for instance sets an environment variable, it will beisolated to the subprocess and disappear as the subprocess exits
Sourcing the file, OTOH, instructs the current shell to read the instructions in said file. In this case changes will modify the current environment. Changed environment variables will be visible after command completion.
Sourcing only works for shell scripts written for the current shell. Execution works for any type of runnable script/program/executable file.
This question already has an answer here:
Best way to set environment variables in calling shell
(1 answer)
Closed 8 years ago.
I have a script "set_var.sh" written like this
#!/bin/bash
export NAME=release
export ROOT=/Volumes/name/dev/release
but if I run this set_var.sh from terminal, afterward I issue set command to check variables I could not find NAME and ROOT var be set.
I am wondering what is wrong in my case.
it was set in sub-shell.
you need
source set_var.sh
If you simply run set_var.sh, it runs in its own shell which exits, losing the variables that were set.
If you want to change variables in your interactive shell, you can use:
source set_var.sh
or the shorthand,
. set_var.sh
This will execute the lines of the script as if they were typed into your interactive shell.
Note that when you "source" a file this way, it does not require the "shebang" on the first line.
Note also that this is feature exists in Bourne shell as well, but only in the short-form version.