2010-07-28 4 views
321

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

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

+0

Вы считали, что где-то, как/usr/bin, записываете сценарий оболочки в каталог (hardcoded), а затем выполняете свой скрипт? –

+2

Зачем вам нужен каталог скрипта? Вероятно, есть лучший способ решить основную проблему. – bstpierre

+9

Я хотел бы указать, что поведение, которое вы называете «явно нежелательным», на самом деле абсолютно необходимо - если я запускаю «путь myscript/to/file», я ожидаю, что скрипт будет оценивать путь/в/файл относительно MY текущий каталог, а не какой-либо каталог, в котором находится скрипт. Кроме того, что бы вы сделали для сценария, запущенного с помощью 'ssh remotehost bash <./myscript', как упоминается в FAQ BASH? –

ответ

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

dirname возвращает '.' при использовании bash под Windows. Итак, ответ Павла лучше. – Tvaroh

+5

Также возвращает '.' в Mac OSX –

+2

Стоит отметить, что все может сломаться, если символическая ссылка составляет часть '$ 0'. В вашем скрипте вы можете ожидать, например, '../../' ссылаться на каталог на два уровня выше расположения сценария, но это не обязательно, если символические ссылки находятся в игре. –

1

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

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

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

+3

'realpath' вряд ли будет установлен повсюду. Что может быть неважно, в зависимости от ситуации ОП. – bstpierre

+0

В моей системе нет 'realpath', но у нее есть' readlink', который кажется похожим. –

+0

Эти команды кажутся опасными в этом контексте – Prospero

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

Это легко. Оно работает.

+1

Это должен быть принятый ответ. Работает на OSX и Linux Ubuntu. –

+3

Это отлично работает, когда сценарий B получен из другого сценария A, и вам нужно использовать пути относительно скрипта B. Спасибо. – Enrico

+1

Это также работает в ** Cygwin ** для тех из нас, кому прискорбно достаточно, чтобы прикоснуться к Windows. –

232

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

cd "${0%/*}" 
+3

Это заслуживает отметки для наиболее кратким ответом. –

+1

При использовании bash для Windows используйте $ {0% [\\ /] *} – Tvaroh

+0

Звучит интересно, но он не работает из текущего каталога (вместо этого вместо него передается имя скрипта). – kenorb

-4

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

$ vim test 

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

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

chmod u+x test 

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

+0

Вопрос в том, как обеспечить выполнение сценария в каталоге _own_, в том числе, если это _not_ рабочий каталог. Так что это не ответ. Во всяком случае, зачем это делать, а не просто ... running 'pwd'? Похоже на то, что у меня много пустых ключей. –

131

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


Для всех 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).


В Баш

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

cd ${0%/*} 

, но он не работает, если скрипт выполняется из того же каталога.

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

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

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

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

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

Похожие:

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

How can I get the behavior of GNU's readlink -f on a Mac?

+4

гораздо лучший ответ, чем популярные, потому что он решает syslinks и учитывает разные ОС. Благодаря! –

+0

Спасибо за этот ответ. Верхняя часть работала на моем Mac ... но что делает-switch в команде 'cp', @kenorb? – TobyG

+3

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

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

Не могли бы вы объяснить ваш ответ, пожалуйста? – Zulu

+1

Хотя этот код может помочь решить проблему, он не объясняет _why_ и/или _how_, он отвечает на вопрос. Предоставление этого дополнительного контекста значительно улучшит его долгосрочную образовательную ценность. Пожалуйста, отредактируйте свой ответ, чтобы добавить объяснение, включая ограничения и допущения. –

-3
echo $PWD 

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

+4

Это дает только вызываемый каталог, а не каталог, где находится скрипт. – dagelf

Смежные вопросы