I am trying to call another shell script from inside a shell script in unix (bash)
1st Shell script(script_1.sh):
VARIABLE_1=<VALUE>
<unix_code>
<unix_code>
..
..
..
export VARIABLE_1
bash -x script_2.sh
bash -x script_3.sh
my requirement here is to pass the value of VARIABLE_1 to script_2.sh & script_3.sh. I was able to execute script_2.sh pass the argument to script_2.sh and it was working fine. Problem has started when i included script_3.sh. It gives me below error, when i execute the first shell script.
/usr/bin/sh: /usr/bin/sh: cannot execute binary file
Not sure why this happening. Also, Is this recommended way to pass arguments and call other shell scripts ? Please let me know
cannot execute binary file does not mean the file lacks execute permissions. In fact, running a script as "bash filename", does not need the executable permissions on the filename.
The error message is telling you that the script file is not an actual script file, but a binary file, probably an executable. If that is the case, do not do:
bash +x filename
just do:
filename
Additionally, to pass arguments to the script, you can do so like this:
scriptfile arg1 arg2 arg3
then refer inside your script as $1, $2, $3. Or $*to refer to all of them.
EDIT:
Also note that to execute a script you do not need to use bash scriptfile, you may just run scriptfile. In that case, scriptfile must have the executable permission (i.e., chmod +x scriptfile). Additionally, if the file is in the current directory, but the . is not part of the PATHvariable, the scriptfile will not be found. In that case you should execute your scriptfile as ./scriptfile
Your script would change to:
VARIABLE_1=<VALUE>
...
./script_2.sh "$VARIABLE_1"
./script_3.sh "$VARIABLE_1"
You no longer need to export the VARIABLE_1. The quotes are necessary to make sure the contents of VARIABLE_1 are passed as a single argument. script_2.sh and script_3.sh will see the value as $1. If the VARIABLE_1 has spaces in it, and you omit the quotes, each word will be pass as a separate value. That is, $1 will have the first word, $2the second, etc.
script_3.sh may not have permission to execute. Use chmod to provide appropriate permission and try again
Related
Suppose I would like to set a shell in make:
SHELL:=/usr/bin/env bash
Next, suppose I have some runcom/bash file I would like to source as well. This file optionally activates a virtual environment:
if [ -d venv ]; then source venv/bin/activate fi;
However, if I write:
SHELL:=/usr/bin/env bash && source runcom/bash
This fails. However, if I deposited the venv logic into the local ~/.bashrc and write:
SHELL:=/usr/bin/env bash -l
I can get the exact functionality I need.
But, I have to deposit something that should remain downstream from the local user into the user's upstream environment -- I'd rather not.
Is there a way to get the make shell to source a file at the declaration step in the make start-up process?
This can't work:
SHELL:=/usr/bin/env bash && source runcom/bash
Because SHELL tells make how to invoke the shell; if you make the contents of SHELL be a shell script then make has to invoke the shell to interpret how to invoke the shell, which means it has to invoke the shell to invoke the shell to interpret how to invoke the shell, etc.
So, SHELL must be either a simple command or, at most, a simple set of arguments that can converted into an argv list and passed to exec(2).
So, this is really a shell question not a make question: how can you get the shell to source arbitrary stuff when it starts without changing ~/.profile or whatever?
Luckily, this is possible; see the bash man page:
BASH_ENV
If this parameter is set when bash is executing a shell script,
its value is interpreted as a filename containing commands to
initialize the shell, as in ~/.bashrc. The value of BASH_ENV is
subjected to parameter expansion, command substitution, and
arithmetic expansion before being interpreted as a filename.
PATH is not used to search for the resultant filename.
ENV Similar to BASH_ENV; used when the shell is invoked in posix
mode.
So, in your makefile you can use something like:
SHELL := /bin/bash
export BASH_ENV := runcom/bash
and that should be sufficient.
I just learned that the bash command opens up a new Bash shell inside of whatever shell you're using, and uses the profile of .bashrc for its commands.
When I was installing Laravel earlier this week, I used a bash init.sh command. Now I'm wondering, what exactly did that bash init.sh command do? Why did I need to open a new shell to... execute or open whatever was in init.sh?
Quoting man bash*:
ARGUMENTS
If arguments remain after option processing, and neither the -c nor the -s option has been supplied, the first argument is assumed to be the name of a file containing shell commands. If bash is invoked in this fashion, $0 is set to the name of the file, and the positional parameters are set to the remaining arguments. Bash reads and executes commands from this file, then exits. Bash's exit status is the exit status of the last command executed in the script. If no commands are executed, the exit status is 0. An attempt is first made to open the file in the current directory, and, if no file is found, then the shell searches the directories in PATH for the script.
In other words: bash <file> executes <file> as a Bash script. You will not get a new interactive shell.
Note that this is not the only way to specify which shell (or indeed any command) should be used to execute a script: It's common to use a shebang for that, so that the script can be ‘executed’ by itself.
* The one I had at hand, of Bash v4.3.42.
I am looking to execute a script but have it include another script before it executes. The problem is, the included script would be generated and the executed script would be unmodifiable. One solution I came up with, was to actually reverse the include, by having the include script as a wrapper, calling set to set the arguments for the executed script and then dotting/sourcing it. E.g.
#!/bin/bash
# Generated wrapper or include script.
: Performing some setup...
target_script=$1 ; shift
set -- "$#"
. "$target_script"
Where target_script is the script I actually want to run, importing settings from the wrapper.
However, the potential problem I face is that callers of the target script or even the target script itself may be expecting $0 to be set to the path of it's location on the file system. But because this wrapper approach overrides $0, the value of $0 may be unexpected and could produce undefined behaviour.
Is there another way to perform what is in effect, an LD_PRELOAD but in the scripted form, through bash without interfering with its runtime parameters?
I have looked at --init-file or --rcfile, but these only seem to be included for interactive shells.
Forcing interactive mode does seem to allow me to specify --rcfile:
$ bash --rcfile /tmp/x-include.sh -i /tmp/xx.sh
include_script: $0=bash, $BASH_SOURCE=/tmp/x-include.sh
target_script: $0=/tmp/xx.sh, $BASH_SOURCE=/tmp/xx.sh
Content of the x-include.sh script:
#!/bin/bash
echo "include_script: \$0=$0, \$BASH_SOURCE=$BASH_SOURCE"
Content of the xx.sh script:
#!/bin/bash
echo "target_script: \$0=$0, \$BASH_SOURCE=$BASH_SOURCE"
From the bash documentation:
When bash is started non-interactively, to run a shell script, for example, it looks for the variable BASH_ENV in
the environment, expands its value if it appears there, and uses the expanded value as the name of a file to read
and execute. Bash behaves as if the following command were executed:
if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
but the value of the PATH variable is not used to search for the file name.
So that settles it then:
BASH_ENV=/tmp/x-include.sh /bin/bash /tmp/xx.sh
I am writing a bash script (called gotodir.sh) and would like to change directories during the course of the script, depending on some variables, say cd /home/username/${FOO}/${BAR}.
Just running this as is doesn't work when the process exits, since the directory was changed in the subshell only.
My shell is tcsh. (Yeah, I know... not my choice here.) In my .cshrc file, I want to alias the keyword gotodir to gotodir.sh.
I have read that executing the script with a . or source prefix will cause the script to be run in the same shell (i.e. not a subshell).
I have tried putting the following in my .cshrc file:
alias gotodir . /home/username/bin/gotodir.sh
but this results in the error: /bin/.: Permission denied.
I have also tried using source instead of .
alias gotodir source /home/username/bin/gotodir.sh
but this results in the error: if: Expression Syntax.
How do I accomplish this using a bash script while running tcsh?
When you source a file from tcsh, it tcsh runs the commands. The #! is ignored as a comment because you're not running the file as a script, just reading commands from it as if they'd been entered at the shell prompt.
Your mission is doomed to failure. Only a tcsh cd command can change the current directory of a tcsh process.
But if you're willing to bend a little, you can write a script which runs as a separate process and outputs the name of the directory to cd to. Then set the alias like
alias gotodir 'cd `/blah/blah/thescript`'
Addendum
Adding an argument is possible, but tricky. Alias arguments look like history expansion, with !:1 expanding to the first argument. But quotes don't protect the ! character. You have to backslash it to prevent it being expanded during creation of the aliase, so it can do its work during the execution of the alias.
alias gotodir 'cd `/blah/blah/thescript \!:1`'
Additional quoting may be required to handle arguments and directories with spaces in them.
I used 'change directory' in my shell script (bash)
#!/bin/bash
alias mycd='cd some_place'
mycd
pwd
pwd prints some_place correctly, but after the script finished my current working directory doesn't change.
Is it possible to change my path by script?
You need to source the file as:
. myfile.sh
or
source myfile.sh
Without sourcing the changes will happen in the sub-shell and not in the parent shell which is invoking the script. But when you source a file the lines in the file are executed as if they were typed at the command line.
While sourcing the script you want to run is one solution, you should be aware that this script then can directly modify the environment of your current shell. Also it is not possible to pass arguments anymore.
Another way to do, is to implement your script as a function in bash.
function cdbm() {
cd whereever_you_want_to_go
echo arguments to the functions were $1, $2, ...
}
This technique is used by autojump:
http://github.com/joelthelion/autojump/wiki
to provide you with learning shell directory bookmarks.
The script is run in a separate subshell. That subshell changes directory, not the shell you run it in. A possible solution is to source the script instead of running it:
# Bash
source yourscript.sh
# or POSIX sh
. yourscript.sh
It can be achieved by sourcing. Sourcing is basically execute the script in the same shell whereas normal execution(sh test.sh or ./test.sh) will create sub shell and execute script there.
test.sh
cd development/
ls
# Do whatever you want.
Execute test.sh by
source test.sh
. is shortest notation for source. So you can also do by
. test.sh
This will execute the script and change the directory of current shell to development/.
whenever you run a script on your login shell, a new subprocess is spawned and the script execution is done in a subshell.Once the script completes, the subshell exits and you are returned to the login shell.Hence whenever you do a cd through a script,the directory is changed to the path specified by cd, but by the time script finishes you come back to your login shell to the working directory from where you started the script.
The way to overcome this is use,
source yourscript.sh
what source does is it executes the script as TCL script, i.e it has the same effect as when you typed each line on the command line of your login shell and it executed from there. So this way when the script finishes after cd , it stays in that directory.
Another practical solution is to end your script by opening another shell session.
For instance:
#!/bin/bash
cd some_place
bash
This is useful, in my case, for scripts located in my ~/bin for instance, called from any other place. It is just a bit painful to type source ~/bin/mygoodoldscript instead of mygoo<TAB><ENTER>.
The downside is that the additional shell takes up a few more resources (not much).
Though there are answers. I think the intention of question is to use script to navigate to specific path.
Here is a simple practical solution works here without cancel out existing terminal environment flag.
provide a bash/tch/sh script to work for path generation
/* .goto.sh */
#!/usr/bin/env bash
echo '~/workspace'
add alias to the script output
alias goto 'cd `.goto.sh`'