Введение
Этот ответ исправляет очень сломленный, но шокирующе лучший голос этой ветки (написанный TheMarko):
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
ПОЧЕМУ ИСПОЛЬЗУЕТСЯ dirname "$ 0" НА ЭТОМ НЕ РАБОТАЕТ?
dirname $ 0 будет работать только в том случае, если пользователь запускает скрипт очень специфическим образом. Мне удалось найти несколько ситуаций, когда этот ответ не удается и происходит сбой сценария.
Прежде всего, давайте разберемся, как работает этот ответ. Он получает каталог скриптов, выполняя
dirname "$0"
$ 0 представляет первую часть команды, вызывающей скрипт (в основном это введенная команда без аргументов:
/some/path/./script argument1 argument2
$ 0 = "/ некоторые / путь /./ сценарий"
dirname в основном находит последний / в строке и обрезает его там. Так что если вы делаете:
dirname /usr/bin/sha256sum
вы получите: / usr / bin
Этот пример хорошо работает, потому что / usr / bin / sha256sum - это правильно отформатированный путь, но
dirname "/some/path/./script"
не сработает и даст вам:
BASENAME="/some/path/." #which would crash your script if you try to use it as a path
Скажем, вы в том же каталоге, что и ваш скрипт, и запускаете его с помощью этой команды
./script
$ 0 в этой ситуации будет ./script и dirname $ 0 даст:
. #or BASEDIR=".", again this will crash your script
Использование:
sh script
Без ввода полного пути также будет получено значение BASEDIR = "."
Использование относительных каталогов:
../some/path/./script
Дает имя $ 0 из:
../some/path/.
Если вы находитесь в каталоге / some и вызываете скрипт таким образом (обратите внимание на отсутствие / в начале, снова относительный путь):
path/./script.sh
Вы получите это значение для dirname $ 0:
path/.
и ./path/./script (еще одна форма относительного пути) дает:
./path/.
Единственные две ситуации, когда basedir $ 0 будут работать, - это если пользователь использует sh или touch для запуска скрипта, потому что оба результата приведут к $ 0:
$0=/some/path/script
, который даст вам путь, который вы можете использовать с dirname.
РЕШЕНИЕ
Вы должны были учесть и обнаружить каждую из вышеупомянутых ситуаций и применить исправление для нее, если оно возникнет:
#!/bin/bash
#this script will only work in bash, make sure it's installed on your system.
#set to false to not see all the echos
debug=true
if [ "$debug" = true ]; then echo "\$0=$0";fi
#The line below detect script's parent directory. $0 is the part of the launch command that doesn't contain the arguments
BASEDIR=$(dirname "$0") #3 situations will cause dirname $0 to fail: #situation1: user launches script while in script dir ( $0=./script)
#situation2: different dir but ./ is used to launch script (ex. $0=/path_to/./script)
#situation3: different dir but relative path used to launch script
if [ "$debug" = true ]; then echo 'BASEDIR=$(dirname "$0") gives: '"$BASEDIR";fi
if [ "$BASEDIR" = "." ]; then BASEDIR="$(pwd)";fi # fix for situation1
_B2=${BASEDIR:$((${#BASEDIR}-2))}; B_=${BASEDIR::1}; B_2=${BASEDIR::2}; B_3=${BASEDIR::3} # <- bash only
if [ "$_B2" = "/." ]; then BASEDIR=${BASEDIR::$((${#BASEDIR}-1))};fi #fix for situation2 # <- bash only
if [ "$B_" != "/" ]; then #fix for situation3 #<- bash only
if [ "$B_2" = "./" ]; then
#covers ./relative_path/(./)script
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/${BASEDIR:2}"; else BASEDIR="/${BASEDIR:2}";fi
else
#covers relative_path/(./)script and ../relative_path/(./)script, using ../relative_path fails if current path is a symbolic link
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/$BASEDIR"; else BASEDIR="/$BASEDIR";fi
fi
fi
if [ "$debug" = true ]; then echo "fixed BASEDIR=$BASEDIR";fi