Retrieve parent directory of script - bash

I'm working on an uninstaller script to delete the parent folder where the script is installed.
/usr/local/Myapplication/Uninstaller/uninstall.sh
So uninstall.sh has to do this:
rm- rf /usr/local/Myapplication
I can retrieve the folder where uninstall resides
SYMLINKS=$(readlink -f "$0")
UNINSTALL_PATH=$(dirname "$SYMLINKS")
But I'm still unsure of the pretty way to get the parent path.
I thought of using sed to demove the "Uninstaller" part of this path, but is there an elegant way to get the path to Myapplication folder to delete it?
Thank you

How about using dirname twice?
APP_ROOT="$(dirname "$(dirname "$(readlink -fm "$0")")")"
The quoting desaster is only necessary to guard against whitespace in paths. Otherwise it would be more pleasing to the eye:
APP_ROOT=$(dirname $(dirname $(readlink -fm $0)))

I put this answer as comment at 2018. But since I got a great feedback about the effectiveness of the solution, I will share it here as well :
# dir of script
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )";
# parent dir of that dir
PARENT_DIRECTORY="${DIR%/*}"

Just get the parent of the parent directory:
my_app_path=$(dirname $(dirname $(readlink -f "$0")))

If you need an absolute path, then you need cd. Otherwise you can just use $(dirname $0)/..
cd $(dirname $0)/..
path=$(pwd)
cd - # go back

the ultimate simple way of getting the parent directory path:
PARENT_DIRECTORY="${PWD%/*}"

Full path to parent dir of script, i.e. "/usr/local/bin/bla": export PARENT_OF_THIS_SCRIPT=$( cd $(dirname $0) ; pwd -P )
Just the most recent parent of script, i.e. "bla": export PARENT_DIR_OF_SCRIPT=$( cd $(dirname $0) ; pwd -P | xargs basename )

Why don't you simply add ../ at the end of the path?

As $0 can have suprising behavior, here is a solution using BASH_SOURCE[0]:
#/bin/bash
PARENT_DIR=$(dirname $(dirname $(readlink -f "${BASH_SOURCE[0]}")))

Related

get folder name with find ... -name command in bash

Trying to get name of venv folder for activating it in bash script located inside the project. Because someone could use for venv another name like 'someones_env'
projectdir=$(cd ../../ && pwd)
echo "$(dirname "$projectdir")"
venvdir=$(find "$(dirname "$projectdir")" -name '*env')
echo "$(dirname "$venvdir")"
source "$(dirname "$venvdir")"/bin/activate
but $venvdir becomes the same as $projectdir instead of 'someones_env'
what am i doing wrong?
thanks
The directory of the *env folder is the project directory, that's why dirname "$venvdir" becomes the same as the project directory. Without dirname it should work.
Also, the directory of ../../ is ../../../, this might also be giving you some issues. If you are already in a directory, there's no need to use dirname. dirname calculates the parent directory.

Script directory path regardless of current/working directory

Is there a way to get the script directory regardless of change in current directory that occurred during script execution.
echo $(dirname "$(readlink -f "$0")")
cd /tmp
echo $(dirname "$(readlink -f "$0")")
/home/user/test
/tmp
In the example above, I need /home/user/test both times, without storing it to a variable.
This should do the job in your script:
dir="$(readlink /proc/$PPID/cwd)"

Bash script get one directory back

I can get my current working directory with
my_dir=$(pwd)
echo $my_dir
/files/work/test
How do I get /files/work I don't want to change directories. I just need to get the /files/work directory.
Try one of these (assuming you didn't manually change $PWD):
echo "${PWD%/*}"
dirname "$PWD"
(cd .. && pwd)
echo `dirname \`pwd\``
It ll result the parent directory of present working directory
You can ascend one directory above:
$ cd ..
or you can dirname to print the one directory above:
$ dirname "/files/work/test"
/files/work

cp cannot stat to ~/ in script

I am having a problem I just can't seem to get over in my bash script.
Whenever I try to copy using cp to home folder in a script I get
cp: cannot stat '~/file.txt': no such file or directory
My code is as follows:
#!/bin/bash
echo "file location"
read a
user inputs ~/file.txt
b=$(basename $a)
cp "$a" . /$b
Please help, it's probably a simple solution but I just can't figure it out.
Filename expansion isn't applied to variables, which can be checked with the following minimal example:
d="~"; ls $d
ls: cannot access ~: No such file or directory
Use the full path: /home/youruser/file.txt.
Alternatively, you can force the globbing with eval (but prefer not to.. it's eval..):
d=$(eval echo "$d")
echo $d # /home/user
You could do something like
expanded_path=$(echo "$d" | "s:^~:$HOME:")
(that is, subtstitute the initial ~ for $HOME manually)
or force the user to use the full path.
eval is evil (definitely for user-supplied input, it is).
If you just want to copy in the current dir while keeping the original name, you can do:
cp "$src" .
No need to play with basename.
You can just replace the ~ with $HOME:
read a
a=${a/\~/$HOME}
Now ~/file will become /home/user/file

mkdir -p vs if [[ ! -d dirname ]]

Is there any reason to use
if [[ ! -d dirname ]]; then mkdir dirname; fi
instead of just
mkdir -p dirname
The first syntax depends on the shell you are using, not the second.
Since both fail if dirname exists not as a directory, no, there's no difference.
-d FILE True if file is a directory.
-p no error if existing, make parent directories as needed.
If dirname does not contain any parents then the two commands behave the same. However if dirname contains parents the -d will not create those. And [[ is shell-dependent.
These two ksh commands are functionally the same since both will create a directory called dirname.
mkdir -p dirname is more elegant.

Resources