Get the Script's Own Directory in POSIX sh
Find the directory of a running POSIX sh script with cd and pwd over dirname of the script path. A symbolic link to the script resolves to the link's directory.
A script needs files that sit next to it, whatever directory it was started from.
mkdir -p bin
cat > bin/where.sh <<'EOF'
#!/bin/sh
dir=$(cd -- "$(dirname -- "$0")" && pwd)
echo "invoked as $0, script dir $dir"
EOF
chmod +x bin/where.sh
./bin/where.sh
(cd bin && ./where.sh)
(cd /tmp && sh "$OLDPWD/bin/where.sh")
ln -s bin/where.sh link.sh
./link.shinvoked as ./bin/where.sh, script dir /tmp/run/S0255-1/w/bin
invoked as ./where.sh, script dir /tmp/run/S0255-1/w/bin
invoked as /tmp/run/S0255-1/w/bin/where.sh, script dir /tmp/run/S0255-1/w/bin
invoked as ./link.sh, script dir /tmp/run/S0255-1/w$0 is the path used to start the script, so dirname -- "$0" gives its directory, and cd followed by pwd turns a relative path into an absolute one. Running it as ./bin/where.sh, from inside bin and by full path all report the same directory. Putting the cd inside $(...) keeps the change in a subshell and leaves the caller's directory alone. See dirname.
When the script is started through a symbolic link, the last line shows that $0 names the link, so the result is the link's directory and not the real one. POSIX has no way to resolve links, so use readlink -f where it exists. A file read with the dot command does not get its own $0; Bash offers BASH_SOURCE for that.