Как установить текущий рабочий каталог в каталог скрипта?

Я пишу сценарий Bash. Мне нужен текущий рабочий каталог, чтобы всегда быть каталогом, в котором находится скрипт.

Поведение по умолчанию состоит в том, что текущий рабочий каталог в скрипте - это оболочка, из которой я его запускаю, но я не хочу этого поведения.

13 ответов

Решение
#!/bin/bash
cd "$(dirname "$0")"

Следующее также работает:

cd "${0%/*}"

Синтаксис подробно описан в этом ответе Stackru.

Попробуйте следующие простые однострочники:


Для всех UNIX/OSX/Linux

dir=$(cd -P -- "$(dirname -- "$0")" && pwd -P)

Примечание. Двойная тире (-) используется в командах для обозначения конца параметров команды, поэтому файлы, содержащие тире или другие специальные символы, не нарушают команду.


Для Linux, Mac и других *BSD:

cd $(dirname $(realpath $0))

С поддержкой пробелов:

cd "$(dirname "$(realpath "$0")")";

Замечания: realpath должен быть установлен в самом популярном дистрибутиве Linux по умолчанию (например, Ubuntu), но в некоторых он может отсутствовать, поэтому его нужно установить.

В противном случае вы можете попробовать что-то подобное (он будет использовать первый существующий инструмент):

cd $(dirname $(readlink -f $0 || realpath $0))

Для Linux:

cd $(dirname $(readlink -f $0))

Использование GNU readlink на *BSD/Mac:

cd $(dirname $(greadlink -f $0))

Примечание: вам нужно иметь coreutils установлен (например, 1. Установите Homebrew, 2. brew install coreutils).


В баш

В bash вы можете использовать расширения параметров для достижения этой цели, например:

cd ${0%/*}

но это не работает, если скрипт запускается из той же директории.

В качестве альтернативы вы можете определить следующую функцию в bash:

realpath () {
  [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}

Эта функция принимает 1 аргумент. Если аргумент уже имеет абсолютный путь, выведите его как есть, иначе выведите $PWD переменная + аргумент имени файла (без ./ префикс).

или вот версия взята из Debian .bashrc файл:

function realpath()
{
    f=$@
    if [ -d "$f" ]; then
        base=""
        dir="$f"
    else
        base="/$(basename "$f")"
        dir=$(dirname "$f")
    fi
    dir=$(cd "$dir" && /bin/pwd)
    echo "$dir$base"
}

Связанные с:

Смотрите также:

Как я могу получить поведение readlink -f GNU на Mac?

cd "$(dirname ${BASH_SOURCE[0]})"

Это просто. Оно работает.

Принятый ответ хорошо работает для сценариев, которые не были символическими ссылками в других местах, например, в $PATH,

#!/bin/bash
cd "$(dirname "$0")"

Однако, если скрипт запускается по символической ссылке,

ln -sv ~/project/script.sh ~/bin/; 
~/bin/script.sh

Это будет компакт-диск в ~/bin/ каталог, а не ~/project/ каталог, который, вероятно, сломает ваш сценарий, если цель cd должен включать зависимости относительно ~/project/

Безопасный ответ по символической ссылке ниже:

#!/bin/bash
cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"

readlink -f Требуется для определения абсолютного пути к потенциально символически связанному файлу.

Кавычки необходимы для поддержки файловых путей, которые потенциально могут содержать пробелы (плохая практика, но небезопасно предполагать, что это не так)

Здесь много правильных ответов, но один, который, как правило, более полезен для меня (чтобы относительные пути сценария оставались предсказуемыми / работающими), - это использовать pushd / popd:

      pushd "$(dirname ${BASH_SOURCE[0]})"
trap popd EXIT

# ./xyz, etc...

Это перенесет каталог исходного файла в стек навигации, тем самым изменив рабочий каталог, но затем, когда сценарий завершится (по любой причине, включая сбой), trap будет работать popd, восстанавливая текущий рабочий каталог скрипта.

Этот скрипт, кажется, работает для меня:

#!/bin/bash
mypath=`realpath $0`
cd `dirname $mypath`
pwd

Командная строка pwd отражает местоположение скрипта как текущего рабочего каталога, независимо от того, откуда я его запускаю.

Я беру это, и это работает.

#!/bin/bash
cd "$(dirname "$0")"
CUR_DIR=$(pwd)

Получить реальный путь к вашему сценарию

if [ -L $0 ] ; then
    ME=$(readlink $0)
else
    ME=$0
fi
DIR=$(dirname $ME)

(Это ответ на тот же мой вопрос здесь: получить имя каталога, в котором выполняется скрипт)

cd "`dirname $(readlink -f ${0})`"

Большинство ответов либо не обрабатывают файлы, которые связаны символическими ссылками через относительный путь, не являются однострочными, либо не обрабатывают BSD (Mac). Решение, которое делает все три:

      HERE=$(cd "$(dirname "$BASH_SOURCE")"; cd -P "$(dirname "$(readlink "$BASH_SOURCE" || echo .)")"; pwd)

Во-первых, cd к концепции каталога сценария в bash. Затем прочитайте ссылку на файл, чтобы увидеть, является ли это символической ссылкой (относительной или иной), и если да, перейдите в этот каталог. Если нет, перейдите в текущий каталог (необходимо, чтобы все было однострочным). Затем отобразите текущий каталог через pwd.

Вы могли бы добавить -- аргументам cd и readlink, чтобы избежать проблем с каталогами, названными как options, но я не беспокоюсь для большинства целей.

Вы можете увидеть полное объяснение с иллюстрациями здесь:

https://www.binaryphile.com/bash/2020/01/12/determining-the-location-of-your-script-in-bash.html

echo $PWD

PWD - это переменная окружения.

Если вам просто нужно распечатать существующую рабочую директорию, тогда вы можете следовать этому.

$ vim test

#!/bin/bash
pwd
:wq to save the test file.

Дать разрешение на выполнение:

chmod u+x test

Затем выполните скрипт ./test тогда вы можете увидеть настоящий рабочий каталог.

Другие вопросы по тегам