Include binary from relative path in bash script - linux

I have a project/bin/ directory which is not included in the PATH. It contains
the binaries project/bin/one and project/bin/two.
A bash script is located in project/shell/script1/run.sh. Now, I want to use the binary from the project/bin folder in the project/shell/script1/run.sh script. I would like to have a global script which can be sourced, and include those binaries automatically.
So, I created a script project/bin/load_bin:
#!/usr/bin/env bash
$local_bin_one='./one'
$local_bin_two='./two'
In my project/shell/script1/run.sh I execute the script:
#!/usr/bin/env bash
source '../../bin/load_bin'
However, when I try to use $local_bin_one I get a file not found error. This is because the $local_bin_one points to ./one instead of ../../bin/one.
Question: How can I find the path of the script that is calling source '../../bin/load_bin' from the project/bin/load_bin script itself?

You can get the path of a Bash script this way:
${0%/*}
That is, take $0 (argv[0], the full path and filename the script was invoked with), and strip off the last slash and what comes after that (equivalent to $(dirname "$0")).
You can then do this:
mydir=${0%/*}
source "$mydir/../../bin/load_bin"
Or you can even do this:
cd ${0%/*}
source '../../bin/load_bin'

Related

how to extract file location of a sourced script within the script

In a script which I call with the "source" command under linux I want to determine the directory where the script is located. Assuming there is a script under $HOME/foo/bar/sourceme and i call the script from $HOME with source $HOME/foo/bar/sourceme I would like to extract within the script that it is located under $HOME/foo/bar. I know that it is possible without source by using
set _dir = `dirname $0`
setenv MY_DIR = `cd $_dir ; pwd`
but this doesn't work when i use a source.

How to execute a bash script without calling its path?

I have the file script.sh in my-directory folder.
How to run this script with the command `script' from the terminal with no regards to the location I am in the terminal?
You can do so by exporting the path where your script in the PATH environment variable, so that you don't ever have to worry about what your actual script's location is, i.e. if your script is present under say /path/to/dir, do
export PATH=$PATH:/path/to/dir
so that your script's path gets appended to an already existing set if paths under PATH, also remember if you run the above from the command-line, it is not permanent and gets lost soon after the session is terminated. To make it permanent add the same line in .bashrc (or) .bash_profile, depending upon your environment.
Or creating a symbolic link from /usr/bin that is what you intent to do you can do something like ln -s /full/path/to/myscript.sh /usr/bin/myscript and then run as just myscript directly from command line. You can also confirm if is properly added by checking the script's location by which command,
$ which myscript
/usr/bin/myscript
Say your directory is /home/Cristian/my-directory then you can make that part of PATH environment variable like export PATH=$PATH:/home/Cristian/my-directory and then you will be able to call it by typing script.sh and not script. If you want it to be called as script then you should name it script and rename the extension.
The export command will make the directory in question part of PATH temporarily. To make it permanent you may want it to part of .bashrc or other shell rc file if you are in other shells.

How bash and other smart shells can find executable files?

They handle executable elfs, scripts and symbolic links from PATH, however what the algorithm of this doing? I'm afraid of I cannot find a source code of this part of a shell.
UDP: Oh, I'm stupid. It looks for EACH executable file in PATH, either directory or ordinary file.
Well, the actual search is performed by find_user_command_in_path() in findcmd.c:553.
The algorithm to search for a command ${foo} is basically:
check if ${foo} is absolute: if it is return this path and stop searching
iterate over all elements in PATH: for p in ${PATH}
construct a path ${p}/${foo} and see if it exists
if it exists and is executable return this path and stop searching
I'm no expert in this area, but I'm almost perfectly sure that on Linux the executable bit in file permissions is all that matters. No sophisticated algorithm needed.
Let's say that we have a file called hello in the current directory, and that the file contains just one line: echo "hello"
If you ran chmod 755 on the file and and you subsequently execute the file, then the bash shell will look through every path that you have listed in the PATH variable of say .bashrc, starting with the first path, until it locates the first path that contains your hello executable. Think of PATH as a linked list and think of the bash shell as going through the linked list of paths, path by path. If the bash shell is not running the hello executable that you want it to run, you have one option: put your hello executable in any one of the preceeding paths.
I am lazy. I don't bother to turn hello into an executable i.e. I am not running the chmod command and I just run
bash hello
where the bash shell is going to look for the hello file in the current directory, fork a bash process and the forked bash process is going to run the hello file before the forked bash process dies.
I am using the bash shell as an example but any other shell will behave the same way.

Execute bash script from one into another directory?

I have 3 directories:
/A/B/C and 1 bash script in C directory.
How can I execute this bash script from A into in C directory.
I understand from your comments that you want your script to have its current working directory to be in A/B/C when it executes. Ok, so you go into directory A:
cd A
and then execute script.sh from there:
(cd B/C; ./script.sh)
What this does is start a subshell in which you first change to the directory you want your script to execute in and then executes the script. Putting it as a subshell prevents it from messing up the current directory of your interactive session.
If it is a long running script that you want to keep in the background you can also just add & at the end like any other command.
Whenever I want to make sure that a script can access files in its local folder, I throw this in near the top of the script:
# Ensure working directory is local to this script
cd "$(dirname "$0")"
It sounds like this is exactly what you're looking for!
Assuming /A/B/C/script.sh is the script, if you're in /A, then you'd type ./B/C/script.sh or bash B/C/script.sh or a full path, /A/B/C/script.sh. If what you mean is that you want that script always to work, then you'll want to add it to your PATH variable.
Go to A, then run your script by providing the path to it:
cd /A
bash B/C/somescript.sh
You could also add C to your PATH variable, making it runnable from anywhere
(i.e. somescript.sh, without the path)
If you want to access the directory the script is stored in, within the script, you can use this one-liner:
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
or simply dirname. Taken from this thread. There are many more suggestions there.
The easy way to make your script execute within C is to simply be in that folder.

How to handle change in the $PWD value in shell script?

I have a shell script executed by a tool.
When it is executed by a this tool then the value of $PWD is set by that tool.
However when I executed the script manually the value of $PWD the current directory of script.
Now I'm using this $PWD environmental variable to locate different file location in the script.
But when I execute it manually the file path get changed and it give unexpected results.
Any suggestion how can I handle this change in the value of $PWD while executing the script manually or by that tool?
If you need access to the directory where the script itself is located, in bash you can use
script_dir=$(readlink -f ${0%/*})
It takes the relative path to the script ($0), cuts off the script name and transforms it to a full path.

Resources