Как скрипт bash может узнать каталог, в котором он установлен, когда он поставляется с. оператор? - PullRequest
11 голосов
/ 07 января 2009

Что я хотел бы сделать, так это включить настройки из файла в мою текущую интерактивную оболочку bash, например:

$. /path/to/some/dir/.settings

Проблема в том, что сценарию .settings также нужно использовать "." оператор, чтобы включить другие файлы, как это:

. .extra_settings

Как мне указать относительный путь для .extra_settings в файле .settings? Эти два файла всегда хранятся в одном каталоге, но путь к этому каталогу будет отличаться в зависимости от того, где эти файлы были установлены.

Оператор всегда знает / path / to / some / dir /, как показано выше. Как файл .settings может узнать каталог, в котором он установлен? Я бы предпочел не иметь процесса установки, который записывает имя установленного каталога.

Ответы [ 5 ]

18 голосов
/ 08 января 2009

Я полагаю, $(dirname "$BASH_SOURCE") будет делать то, что вы хотите, пока файл, который вы используете, не символическая ссылка.

Если исходный файл может быть символической ссылкой, вы можете сделать что-то вроде следующего, чтобы получить истинный каталог:

PRG="$BASH_SOURCE"
progname=`basename "$BASH_SOURCE"`

while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '/.*' > /dev/null; then
        PRG="$link"
    else
        PRG=`dirname "$PRG"`"/$link"
    fi
done

dir=$(dirname "$PRG")
7 голосов
/ 14 ноября 2013

Вот что может быть элегантным решением:

script_path="${BASH_SOURCE[0]}"
script_dir="$(cd "$(dirname "${script_path}")" && pwd)"

Это, однако, не будет работать при поиске ссылок. В этом случае можно сделать

script_path="$(readlink -f "$(readlink "${BASH_SOURCE[0]}")")"
script_dir="$(cd "$(dirname "${script_path}")" && pwd)"

На что обратить внимание:

  • массивы типа ${array[x]} не совместимы с POSIX, но в любом случае массив BASH_SOURCE доступен только в Bash
  • на macOS, собственный BSD readlink не поддерживает -f, поэтому вам, возможно, придется установить GNU readlink, например, с помощью. Заварить на brew install coreutils и заменить readlink на greadlink
  • , в зависимости от вашего варианта использования, вы можете использовать вместо -f переключатели -e или -m плюс, возможно, -n; см. readlink справочную страницу для деталей
2 голосов
/ 07 января 2009

Другой подход к проблеме - если вы используете "." для того, чтобы установить переменные окружения, другой стандартный способ сделать это состоит в том, чтобы использовать в вашем скрипте команды установки переменных эха, например ::

# settings.sh
echo export CLASSPATH=${CLASSPATH}:/foo/bar

затем оцените вывод:

eval $(/path/to/settings.sh)

Так работают пакеты типа modules . Этот способ также облегчает поддержку оболочек, производных от sh (X=...; export X) и csh (setenv X ...)

0 голосов
/ 08 января 2009

Такого рода работы. Это работает в том смысле, что вы можете использовать синтаксис $ (dirname $ 0) в файле .settings, чтобы определить его домашний каталог, поскольку вы выполняете этот скрипт в новой оболочке. Тем не менее, он добавляет дополнительный слой свертки, где вам нужно изменить строки, такие как:

export MYDATE=$(date)

до

echo "export MYDATE=\$(date)"

Может быть, это единственный путь?

0 голосов
/ 07 января 2009

Я попытался возиться с вариантами $ (dirname $ 0), но это не удалось, когда файл .settings включен с ".". Если бы я выполнял файл .settings вместо его включения, это решение работало бы. Вместо этого $ (dirname $ 0) всегда возвращает «.», Что означает текущий каталог. Это не получается, когда вы делаете что-то вроде этого:

$ кд / $. /some/path/.settings

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...