Skip to content

Instantly share code, notes, and snippets.

@ptc-mrucci
Forked from tvlooy/unit.sh
Last active March 31, 2023 10:49
Show Gist options
  • Save ptc-mrucci/61772387878ed53a6c717d51a21d9371 to your computer and use it in GitHub Desktop.
Save ptc-mrucci/61772387878ed53a6c717d51a21d9371 to your computer and use it in GitHub Desktop.
Bash test: get the directory of a script
#!/bin/bash
tmp=$(python -c "import os, sys; print(os.path.realpath('/tmp'))")
function test {
MESSAGE=$1
RECEIVED=$2
EXPECTED=$3
if [ "$RECEIVED" = "$EXPECTED" ]; then
echo -e "\033[32m✔︎ Tested $MESSAGE"
else
echo -e "\033[31m✘ Tested $MESSAGE"
echo -e " Received: $RECEIVED"
echo -e " Expected: $EXPECTED"
fi
echo -en "\033[0m"
}
function testSuite {
test 'absolute call' `bash $tmp/1234/test.sh` $tmp/1234
test 'via symlinked dir' `bash $tmp/current/test.sh` $tmp/1234
test 'via symlinked file' `bash $tmp/test.sh` $tmp/1234
test 'via multiple symlinked dirs' `bash $tmp/current/loop/test.sh` $tmp/1234
pushd $tmp >/dev/null
test 'relative call' `bash 1234/test.sh` $tmp/1234
popd >/dev/null
test 'with space in dir' "`bash $tmp/12\ 34/test.sh`" $tmp/1234
test 'with space in file' `bash $tmp/1234/te\ st.sh` $tmp/1234
echo
}
function setup {
DIR=$tmp/1234
FILE=test.sh
if [ -e $DIR ]; then rm -rf $DIR; fi; mkdir $DIR
if [ -f $DIR/$FILE ]; then rm -rf $DIR/$FILE; fi; touch $DIR/$FILE
if [ -f $tmp/$FILE ]; then rm $tmp/$FILE; fi; ln -s $DIR/$FILE $tmp
if [ -f $tmp/current ]; then rm $tmp/current; fi; ln -s $DIR $tmp/current
if [ -f $tmp/current/loop ]; then rm $tmp/current/loop; fi; ln -s $DIR $tmp/current/loop
DIR2="$tmp/12 34"
FILE2="te st.sh"
if [ -e "$DIR2" ]; then rm -rf "$DIR2"; fi; mkdir "$DIR2"
if [ -f "$DIR/$FILE2" ]; then rm -rf "$DIR/$FILE2"; fi; ln -s $DIR/$FILE "$DIR/$FILE2"
if [ -f "$DIR2/$FILE" ]; then rm -rf "$DIR2/$FILE"; fi; ln -s $DIR/$FILE "$DIR2/$FILE"
if [ -f "$DIR2/$FILE2" ]; then rm -rf "$DIR2/$FILE2"; fi; ln -s $DIR/$FILE "$DIR2/$FILE2"
}
function test1 {
echo 'Test 1: via dirname'
cat <<- 'EOF' >$tmp/1234/test.sh
echo `dirname $0`
EOF
testSuite
}
function test2 {
echo 'Test 2: via pwd'
cat <<- 'EOF' >$tmp/1234/test.sh
CACHE_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
echo $CACHE_DIR
EOF
testSuite
}
function test3 {
echo 'Test 3: overcomplicated stackoverflow solution'
cat <<- 'EOF' >$tmp/1234/test.sh
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
SOURCE="$(readlink "$SOURCE" 2> /dev/null)"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
done
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
echo $DIR
EOF
testSuite
}
function test4 {
echo 'Test 4: via readlink'
cat <<- 'EOF' >$tmp/1234/test.sh
echo `dirname $(readlink -f $0 2> /dev/null)`
EOF
testSuite
}
function test5 {
echo 'Test 5: via readlink with space'
cat <<- 'EOF' >$tmp/1234/test.sh
echo `dirname $(readlink -f "$0" 2> /dev/null)`
EOF
testSuite
}
function test6 {
echo 'Test 6: as Test 2 but with cd -P';
cat <<- 'EOF' >$tmp/1234/test.sh
CACHE_DIR=$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
echo $CACHE_DIR
EOF
testSuite
}
function test7 {
echo 'Test 7: via cd -P and pwd, testing for symlinked file first';
cat <<- 'EOF' >$tmp/1234/test.sh
__SOURCE__="${BASH_SOURCE[0]}"
while [[ -h "${__SOURCE__}" ]]; do
# shellcheck disable=SC1117
__SOURCE__=$(find "${__SOURCE__}" -type l -ls | sed -n 's/^.* -> \(.*\)/\1/p');
done;
echo $(cd -P "$( dirname "${__SOURCE__}" )" && pwd)
EOF
testSuite
}
function test8 {
echo 'Test 8: ${0%/*}'
cat <<- 'EOF' >$tmp/1234/test.sh
echo "${0%/*}"
EOF
testSuite
}
function test9 {
echo 'Test 9: python os.path functions'
cat <<- 'EOF' >$tmp/1234/test.sh
echo $(python -c "import os; print(os.path.dirname(os.path.realpath('${BASH_SOURCE[0]}')))")
EOF
testSuite
}
function test10 {
echo 'Test 10: python3 pathlib functions'
cat <<- 'EOF' >$tmp/1234/test.sh
echo $(python3 -c "from pathlib import Path; print(Path('${BASH_SOURCE[0]}').resolve().parent)")
EOF
testSuite
}
function test11 {
echo 'Test 11: oneliner from Binary Phile (https://stackoverflow.com/a/67149152/133106)'
cat <<- 'EOF' >$tmp/1234/test.sh
echo $(cd "$(dirname "$BASH_SOURCE")"; cd -P "$(dirname "$(readlink "$BASH_SOURCE" || echo .)")"; pwd)
EOF
testSuite
}
echo
setup
if [ "$1" != "" ]; then
$1
else
test1
test2
test3
test4
test5
test6
test7
test8
test9
test10
test11
fi
@riley-martine
Copy link

MacOS, system bash and readlink:

$ /bin/bash unit.sh

Test 1: via dirname
✔︎ Tested absolute call
✘ Tested via symlinked dir
  Received: /private/tmp/current
  Expected: /private/tmp/1234
✘ Tested via symlinked file
  Received: /private/tmp
  Expected: /private/tmp/1234
✘ Tested via multiple symlinked dirs
  Received: /private/tmp/current/loop
  Expected: /private/tmp/1234
✘ Tested relative call
  Received: 1234
  Expected: /private/tmp/1234
✘ Tested with space in dir
  Received: /private/tmp 34
  Expected: /private/tmp/1234
✘ Tested with space in file
  Received: /private/tmp/1234
  Expected: .

Test 2: via pwd
✔︎ Tested absolute call
✘ Tested via symlinked dir
  Received: /private/tmp/current
  Expected: /private/tmp/1234
✘ Tested via symlinked file
  Received: /private/tmp
  Expected: /private/tmp/1234
✘ Tested via multiple symlinked dirs
  Received: /private/tmp/current/loop
  Expected: /private/tmp/1234
✔︎ Tested relative call
✘ Tested with space in dir
  Received: /private/tmp/12 34
  Expected: /private/tmp/1234
✔︎ Tested with space in file

Test 3: overcomplicated stackoverflow solution
✔︎ Tested absolute call
✔︎ Tested via symlinked dir
✔︎ Tested via symlinked file
✔︎ Tested via multiple symlinked dirs
✔︎ Tested relative call
✔︎ Tested with space in dir
✔︎ Tested with space in file

Test 4: via readlink
✔︎ Tested absolute call
✔︎ Tested via symlinked dir
✔︎ Tested via symlinked file
✔︎ Tested via multiple symlinked dirs
✔︎ Tested relative call
usage: dirname string [...]
✘ Tested with space in dir
  Received:
  Expected: /private/tmp/1234
usage: dirname string [...]
✘ Tested with space in file
  Received: /private/tmp/1234
  Expected:

Test 5: via readlink with space
✔︎ Tested absolute call
✔︎ Tested via symlinked dir
✔︎ Tested via symlinked file
✔︎ Tested via multiple symlinked dirs
✔︎ Tested relative call
✔︎ Tested with space in dir
✔︎ Tested with space in file

Test 6: as Test 2 but with cd -P
✔︎ Tested absolute call
✔︎ Tested via symlinked dir
✘ Tested via symlinked file
  Received: /private/tmp
  Expected: /private/tmp/1234
✔︎ Tested via multiple symlinked dirs
✔︎ Tested relative call
✘ Tested with space in dir
  Received: /private/tmp/12 34
  Expected: /private/tmp/1234
✔︎ Tested with space in file

Test 7: via cd -P and pwd, testing for symlinked file first
✔︎ Tested absolute call
✔︎ Tested via symlinked dir
✔︎ Tested via symlinked file
✔︎ Tested via multiple symlinked dirs
✔︎ Tested relative call
✔︎ Tested with space in dir
✔︎ Tested with space in file

Test 8: ${0%/*}
✔︎ Tested absolute call
✘ Tested via symlinked dir
  Received: /private/tmp/current
  Expected: /private/tmp/1234
✘ Tested via symlinked file
  Received: /private/tmp
  Expected: /private/tmp/1234
✘ Tested via multiple symlinked dirs
  Received: /private/tmp/current/loop
  Expected: /private/tmp/1234
✘ Tested relative call
  Received: 1234
  Expected: /private/tmp/1234
✘ Tested with space in dir
  Received: /private/tmp/12 34
  Expected: /private/tmp/1234
✔︎ Tested with space in file

Test 9: python os.path functions
✔︎ Tested absolute call
✔︎ Tested via symlinked dir
✔︎ Tested via symlinked file
✔︎ Tested via multiple symlinked dirs
✔︎ Tested relative call
✔︎ Tested with space in dir
✔︎ Tested with space in file

Test 10: python3 pathlib functions
✔︎ Tested absolute call
✔︎ Tested via symlinked dir
✔︎ Tested via symlinked file
✔︎ Tested via multiple symlinked dirs
✔︎ Tested relative call
✔︎ Tested with space in dir
✔︎ Tested with space in file

Test 11: oneliner from Binary Phile (https://stackoverflow.com/a/67149152/133106)
✔︎ Tested absolute call
✔︎ Tested via symlinked dir
✔︎ Tested via symlinked file
✔︎ Tested via multiple symlinked dirs
✔︎ Tested relative call
✔︎ Tested with space in dir
✔︎ Tested with space in file

debian:latest (needed to install python2 and python3):

# /bin/bash unit.sh

Test 1: via dirname
✔︎ Tested absolute call
✘ Tested via symlinked dir
  Received: /tmp/current
  Expected: /tmp/1234
✘ Tested via symlinked file
  Received: /tmp
  Expected: /tmp/1234
✘ Tested via multiple symlinked dirs
  Received: /tmp/current/loop
  Expected: /tmp/1234
✘ Tested relative call
  Received: 1234
  Expected: /tmp/1234
✘ Tested with space in dir
  Received: /tmp 34
  Expected: /tmp/1234
✘ Tested with space in file
  Received: /tmp/1234
  Expected: .

Test 2: via pwd
✔︎ Tested absolute call
✘ Tested via symlinked dir
  Received: /tmp/current
  Expected: /tmp/1234
✘ Tested via symlinked file
  Received: /tmp
  Expected: /tmp/1234
✘ Tested via multiple symlinked dirs
  Received: /tmp/current/loop
  Expected: /tmp/1234
✔︎ Tested relative call
✘ Tested with space in dir
  Received: /tmp/12 34
  Expected: /tmp/1234
✔︎ Tested with space in file

Test 3: overcomplicated stackoverflow solution
✔︎ Tested absolute call
✔︎ Tested via symlinked dir
✔︎ Tested via symlinked file
✔︎ Tested via multiple symlinked dirs
✔︎ Tested relative call
✔︎ Tested with space in dir
✔︎ Tested with space in file

Test 4: via readlink
✔︎ Tested absolute call
✔︎ Tested via symlinked dir
✔︎ Tested via symlinked file
✔︎ Tested via multiple symlinked dirs
✔︎ Tested relative call
✘ Tested with space in dir
  Received: /tmp
  Expected: /tmp/1234
✘ Tested with space in file
  Received: /tmp/1234
  Expected: /

Test 5: via readlink with space
✔︎ Tested absolute call
✔︎ Tested via symlinked dir
✔︎ Tested via symlinked file
✔︎ Tested via multiple symlinked dirs
✔︎ Tested relative call
✔︎ Tested with space in dir
✔︎ Tested with space in file

Test 6: as Test 2 but with cd -P
✔︎ Tested absolute call
✔︎ Tested via symlinked dir
✘ Tested via symlinked file
  Received: /tmp
  Expected: /tmp/1234
✔︎ Tested via multiple symlinked dirs
✔︎ Tested relative call
✘ Tested with space in dir
  Received: /tmp/12 34
  Expected: /tmp/1234
✔︎ Tested with space in file

Test 7: via cd -P and pwd, testing for symlinked file first
✔︎ Tested absolute call
✔︎ Tested via symlinked dir
✔︎ Tested via symlinked file
✔︎ Tested via multiple symlinked dirs
✔︎ Tested relative call
✔︎ Tested with space in dir
✔︎ Tested with space in file

Test 8: ${0%/*}
✔︎ Tested absolute call
✘ Tested via symlinked dir
  Received: /tmp/current
  Expected: /tmp/1234
✘ Tested via symlinked file
  Received: /tmp
  Expected: /tmp/1234
✘ Tested via multiple symlinked dirs
  Received: /tmp/current/loop
  Expected: /tmp/1234
✘ Tested relative call
  Received: 1234
  Expected: /tmp/1234
✘ Tested with space in dir
  Received: /tmp/12 34
  Expected: /tmp/1234
✔︎ Tested with space in file

Test 9: python os.path functions
✔︎ Tested absolute call
✔︎ Tested via symlinked dir
✔︎ Tested via symlinked file
✔︎ Tested via multiple symlinked dirs
✔︎ Tested relative call
✔︎ Tested with space in dir
✔︎ Tested with space in file

Test 10: python3 pathlib functions
✔︎ Tested absolute call
✔︎ Tested via symlinked dir
✔︎ Tested via symlinked file
✔︎ Tested via multiple symlinked dirs
✔︎ Tested relative call
✔︎ Tested with space in dir
✔︎ Tested with space in file

Test 11: oneliner from Binary Phile (https://stackoverflow.com/a/67149152/133106)
✔︎ Tested absolute call
✔︎ Tested via symlinked dir
✔︎ Tested via symlinked file
✔︎ Tested via multiple symlinked dirs
✔︎ Tested relative call
✔︎ Tested with space in dir
✔︎ Tested with space in file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment