Script location execution - bash

I've been working on a script but always with a fixed directory (/opt/mw/script).
I need to change that to be able to execute the script from any directory.
I think I will need to add a "." at the beginning of the line to be able to execute the script?
For example ./mw/script
Is this correct?
Thanks

You already can execute that script from any directory with that absolute file path. It's the relative file paths (that start with ./ or ../) that can only be executed from a specific directory.

You need to add the "." if the script is in the current directory (e.g. ./script), but it is optional if the script is already inside another directory (e.g. mw/script).
Also notice that if your script contains relative references to other files and directories, you may need to use this trick to properly refer to them from any directory.
For instance, consider the following script using absolute paths:
#!/bin/bash
# lists all files in this directory
ls /opt/mw
If it is converted to relative paths as follows:
#!/bin/bash
# lists all files in this directory
ls mw
Then this script will only work if you run it from its own directory (e.g. cd /opt/ && ./script).
But then you can generalize it like this:
#!/bin/bash
SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
# lists all files in this directory
ls $SCRIPT_DIR/mw
Now the script works even when executed from another directory.

Related

Shell Script - opening files from a different directory

I am trying to cd to a different directory by using a path to open a file, but it fails to load correctly.
I am in the directory of ~/Dev/.../Examples to run a ./test.sh script.
Inside the shell script, I have the following:
#!/bin/bash
path = '~/Datasets/foo'
....
"path"/bar
The Dataset folder is right after cd ~/
I have tried $HOME instead of ~, but it still fails to load the respective file.
Here is a code to open the bar directory with nautilus (ubuntu's explorer):
#!/bin/bash
path='/home/your_user_name/foo'
nautilus $path/bar/
Rules:
Use absolute path: /home/your_user_name/, not ~/ nor $HOME.
Bash doesn't like spaces: path='~/Datasets/foo', and not path = '~/Datasets/foo'

Double Clicking a shell script on Mac

i have a small script that runs a jar file :
#!/bin/bash
prefix="foo";
name=`ls ${prefix}*.jar`;
echo $name;
java -jar $name prop1.properties prop2.properties
when i run it in the terminal using ./myscript.sh, it works fine and the jar file executes, but when i rename it in myscript.command and double click it, i have this error :
ls: foo*.jar : No such file or directory
I saw that apparently a .command file opens a terminal at the root directory, so I tried finding the directory containing myscript.command using that :
dir = 'find <dir> -maxdepth 1 -type d -name '*myDirContainingJar*' -print -quit'
cd $dir
but dir is just blank, any ideas ???
Opening a shell script from Finder on macOS (whether it has extension .command or is an extension-less executable shell script) makes the current user's home directory the current directory (as of macOS 10.12).
To explicitly change to the directory in which the script itself is located in a bash script, use:
cd -- "$(dirname -- "$BASH_SOURCE")"
In this invocation scenario, the following POSIX-compliant variation, which uses $0 in lieu of $BASH_SOURCE, would work too: cd -- "$(dirname -- "$0")"
Note:
Generally, if your script is invoked via a symlink and you want to change to the target's directory (the actual script file's directory as opposed to the directory in which the symlink is located), more work is needed - see this answer of mine.
When opening a script from Finder, however, this issue does not apply, because Finder itself resolves a symlink to its (ultimate) target and then invokes the target directly.
The problem with your script is that it runs with a different working directory than you tested it with. When you do ls something in a script, the script looks in the current working directory (where you cded last in case you're in a terminal), not in the directory the script is in. In general, when writing scripts like this you should use the full path of the file you're referring to or figure out the directory of the script and point to the file relative to that. One solution works in Bash, but it might not in the shell you're using.

cp hundreds of files to different directories

The title not might be the best, I apologize, I'm rather new to scripting.
I'm trying to copy 2 files from each directory and place these compounds in a separate directory that only shares directory names.
for clarity;
/path/to/directory/all/variable_directories/
Inside this directory will be multiple files, I need 2 files which will have the same name in every individual variable directory.
I am trying to copy these 2 files from each individual variable directory and put them in variable directories based on the basename of /variable_directory/
the copy destination will be;
/path/to/magical/shit/subset/set_with_variable_name/variable_directories/
Only some of the destination directories are located in each /set_with_variable_name/
The script will need to be able to go through each /set_with_variable_name/ until it finds the directory that shares the basename of the directory that these files are originally being cp'd from
There's about 100 directories
to cp from and to and about 200 files total that need to be copied and sorted appropriately.
I can get it to cp ALL the files to the SAME directory using;
#! /usr/bin/env bash
for i in */;
do cd $i;
cp filename /path/to/destination/;
cp other_filename /path/to/destination/;
cd ..;
done;
It's the sorting the files to the correct destinations that I am completely lost at.
I appreciate any help, I'm a novice to this type of scripting
Looks like you need something like that.
# looping through all the variable directories
for var_dir in <path1>/all/*; do
# creating the destination directory if not exists
mkdir -p "<path2>/set_with_variable_name/$(basename ${var_dir})"
# copying the first file
cp "${var_dir}/filename1" "<path2>/set_with_variable_name/$(basename ${var_dir})/filename1"
# and the second
cp "${var_dir}/filename2" "<path2>/set_with_variable_name/$(basename ${var_dir})/filename2"
done

Always get the full path of a relative file in bash

I have a bash script located in /home/http/mywebsite/bin/download.sh
I have a config file in /home/http/mywebsite/config/config.yaml
Now I want to read the yaml file no matter where I execute my script.
The problem:
When I cd into /home/http/mywebsite/bin/ and run ./download.sh everything works.
When I cd into /home/ and run http/mywebsite/bin/download.sh it can not find the config file because of the relative path.
How do I make sure I can always read the config file no matter where I execute the script. It is always located 4 directories up from the script in config/config.yaml
The script looks like this:
#!/bin/bash
# This will give me the root directory of my project which is /home/http/mywebsite/
fullpath="$( cd ../"$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cat ${fullpath}config/config.yaml
This works if I execute it inside the directory where the script is.
If I execute the script from another directory such as /home/ I get the following error:
cd: ../http/mywebsite/bin: No such file or directory
cat: config/config.yaml: No such file or directory
Solution?
If it is possible it would be great with a code snippet that can traverse up a path N amount of times, this would solve my problem. But it is too advanced for me.
For example you can set a variable "cd_up=1" how many times to go up. The run the loop/sed or whatever magic.
And it would turn the absolute string from:
/home/http/mywebsite/bin/
into:
/home/http/mywebsite/
And changing it to 2 it would change the string to:
/home/http/
Managed to solve it finally by using:
#!/bin/bash
cd "$(dirname "$0")"
BASE_DIR=$PWD
# Root directory to the project
ROOT_DIR=${BASE_DIR}/../
cat ${ROOT_DIR}config/config.yaml
This allows me to execute the script no matter where I am.
You can use which command to determine absolute path of the executing script no matter where you are running
BASE_DIR=$(which $0 | xargs dirname)
ROOT_DIR=${BASE_DIR}/../..
cat ${ROOT_DIR}/config/config.yaml
Lets try printing the path from different locations.
-bash-4.1$ /tmp/dir.sh
$0 - /tmp/dir.sh. Absolute path - /tmp
-bash-4.1$ cd /tmp
-bash-4.1$ ./dir.sh
$0 - ./dir.sh. Absolute path - /tmp
-bash-4.1$
-bash-4.1$ cd /usr/bin
-bash-4.1$ ../../tmp/dir.sh
$0 - ../../tmp/dir.sh. Absolute path - /tmp

Adding shortcut(soft-link) of a directory to global PATH so that it can be accessed from everywhere

I'm trying to put all my symlinks in one directory (I'll call this symlinks directory). I've exported the path of that directory and put it in my .bashrc file. The symlinks to executable applications are running fine but I'm having hard time making symlinks for my directory. This is what I tried.
ln -s ~/mydir/ m
where m is supposed to be my symlink to mydir directory.
This works only when I'm inside symlinks directory. Trying cd m or even just m didn't work from outside that directory. I get:-
bash: cd: m: No such file or directory
Okay, so I thought maybe the PATH doesn't recognize directory paths. So I tried creating a bash script.
#!/bin/sh
cd ~/mydir/
Tried this, m...permission denied. Okay I thought and did chmod +x m to that file. And when I run that script like m then nothing. I tried ./m, still nothing.
I'm close to losing my mind to do such a simple task.
PATH is used to look for commands and I think a command ought to be a file or a symlink to a file.
So, cd m doesn't work as here the command is "cd" (not m). The lookup for "m" does not happen in PATH.
Just m does not work as the "m" found in PATH is a link to a directory and not a file. You can try creating another "m" which points to a file and put it in a directory later in the PATH and it will be recognized when you run just m.
The script you created does work, except that the cd now happens in a new shell and is lost at the end of the script. You can check this by putting an ls after the cd in your script.
There are a few ways to achieve what you want to do.
One option is to use the CDPATH variable. This is the search path for the cd command. Check man bash for details but basically, all you need to do is add your symlinks directory to CDPATH.
export CDPATH=~/symlinks:$CDPATH
cd m ## will cd to linked directory
Alternatively, you can create aliases or functions and put it in your .bashrc or another file which you then source.
alias m="cd ~/mydir"
m() {
cd ~/mydir
}
And now you can just type m to cd to mydir

Resources