Как мне получить путь к каталогу, в котором находится скрипт Bash , внутри этого скрипта?
Я хочу использовать скрипт Bash в качестве средства запуска для другого приложения. Я хочу изменить рабочий каталог на тот, где находится скрипт Bash, чтобы я мог работать с файлами в этом каталоге, например так:
$ ./application
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd && echo x)"
- и удалить ее без подстановки команды -DIR="${DIR%x}"
.mkdir $'\n'
.dirname
, и что каталог может начинаться с-
(например--help
).DIR=$(reldir=$(dirname -- "$0"; echo x); reldir=${reldir%?x}; cd -- "$reldir" && pwd && echo x); DIR=${DIR%?x}
, Возможно, это излишне?Ответы:
полезный однострочный, который даст вам полное имя каталога скрипта независимо от того, откуда он вызывается.
Он будет работать до тех пор, пока последний компонент пути, используемый для поиска сценария, не является символической ссылкой (ссылки на каталоги в порядке). Если вы также хотите разрешить любые ссылки на сам скрипт, вам нужно многострочное решение:
Это последний будет работать с любой комбинацией псевдонимов,
source
,bash -c
, символьные ссылки и т.д.Осторожно: если вы
cd
запустили другой каталог перед запуском этого фрагмента, результат может быть неверным!Кроме того, следите за побочными эффектами
$CDPATH
getchas и stderr, если у пользователя есть умный переопределенный cd для перенаправления вывода на stderr (включая escape-последовательности, например, при вызовеupdate_terminal_cwd >&2
на Mac). Добавление>/dev/null 2>&1
в конце вашейcd
команды позаботится об обеих возможностях.Чтобы понять, как это работает, попробуйте запустить эту более подробную форму:
И это напечатает что-то вроде:
источник
source <script>
иbash <script>
:DIR="$(cd -P "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
.cd
печатает что-то для STDOUT! Например, если у вас$CDPATH
есть.
. Чтобы покрыть этот случай, используйтеDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )"
dirname $(readlink -f $0)
это правильная команда. См. Gist.github.com/tvlooy/cbfbdb111a4ebad8b93e для тестаdirname "$(readlink -f "$0")"
не добавляет сложности и справедливо более надежно для минимального количества проблем.readlink -f $0
даетreadlink: illegal option -- f
.Используйте
dirname "$0"
:использование по
pwd
одному не будет работать, если вы не запускаете скрипт из каталога, в котором он содержится.источник
type -p
если скрипт исполняемый. Это также может открыть тонкую дыру, если скрипт выполняется с использованиемbash test2.sh
и есть другой скрипт с тем же именем, исполняемый где-то еще.bash
а в строке хэш-бенга явно упоминается,/bin/bash
я бы сказал, что довольно безопасно зависеть от ошибок.dirname $0
заключается в том, что если каталог является текущим каталогом, вы получите.
. Это нормально, если вы не собираетесь изменять каталоги в сценарии и ожидать, что вы будете использовать путь, который вы получили,dirname $0
как если бы он был абсолютным. Для того, чтобы получить абсолютный путь:pushd `dirname $0` > /dev/null
,SCRIPTPATH=`pwd`
,popd > /dev/null
: pastie.org/1489386 (Но , конечно , есть лучший способ расширить этот путь?)dirname $0
это проблема, если вы назначаете ее переменной, а затем используете ее для запуска скрипта, подобного$dir/script.sh
; Я предполагаю, что это вариант использования для такого типа вещей в 90% случаев../script.sh
будет работать нормально.Эта
dirname
команда является самой базовой, она просто разбирает путь до имени файла из$0
переменной (имя скрипта):Но, как указал matt b , возвращаемый путь отличается в зависимости от того, как вызывается скрипт.
pwd
не выполняет работу, потому что это говорит только о том, что текущий каталог, а не каталог, в котором находится скрипт. Кроме того, если выполняется символическая ссылка на скрипт, вы получите (возможно, относительный) путь к где находится ссылка, а не фактический скрипт.Некоторые другие упоминали
readlink
команду, но в простейшем случае вы можете использовать:readlink
разрешит путь сценария к абсолютному пути от корня файловой системы. Таким образом, любые пути, содержащие одинарные или двойные точки, тильды и / или символические ссылки, будут преобразованы в полный путь.Вот скрипт, демонстрирующий каждый из них
whatdir.sh
:Запуск этого скрипта в моем домашнем каталоге, используя относительный путь:
Опять же, но с использованием полного пути к сценарию:
Теперь меняем каталоги:
И наконец, используя символическую ссылку для выполнения скрипта:
источник
readlink
не будет доступен на некоторых платформах при установке по умолчанию. Старайтесь избегать его использования, если можетеexport SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
-f
не распознается как опцияreadlink
. Использованиеstat -f
вместо этого делает работу. Спасибоgreadlink
, который в основномreadlink
нам всем знаком. Вот независимая от платформы версия:dir=`greadlink -f ${BASH_SOURCE[0]} || readlink -f ${BASH_SOURCE[0]}`
greadlink
можно легко установить с помощью доморощенного:brew install coreutils
Работает для всех версий, в том числе
source
".
оператор (точка).$0
модифицируется от вызывающей стороны."./script"
"/full/path/to/script"
"/some/path/../../another/path/script"
"./some/folder/script"
В качестве альтернативы, если сам скрипт bash является относительной символической ссылкой, вы хотите перейти по нему и вернуть полный путь связанного сценария:
SCRIPT_PATH
дается в полном пути, независимо от того, как это называется.Просто убедитесь, что вы нашли это в начале скрипта.
Этот комментарий и код Copyleft, выбираемая лицензия под GPL2.0 или выше или CC-SA 3.0 (CreativeCommons Share Alike) или позже. (c) 2008. Все права защищены. Никаких гарантий. Вы были предупреждены.
http://www.gnu.org/licenses/gpl-2.0.txt
http://creativecommons.org/licenses/by-sa/3.0/
18eedfe1c99df68dc94d4a94712a71aaa8e1e9e36cacf421b9463dd2bbaa02906d0d6656
источник
readlink -f $(dirname "${VIRTUAL_ENV}")
;dirname "${SCRIPT_PATH}"
&& pwd)? Но в любом случае отличный сценарий!cd
выходить из своего текущего каталога в надеждеcd
вернуться снова позже: у сценария может не быть разрешения изменить каталог обратно в каталог, который был текущим на момент его вызова. (То же самое касается pushd / popd)readlink -f
является специфичным для GNU. У BSDreadlink
такой опции нет.([ ... ])
менее эффективен[ ... ]
, и нет никакой выгоды от изоляции, предлагаемой взамен этой производительности.Короткий ответ:
или ( предпочтительно ):
источник
source
их, и ихcd $(dirname $0)
легко запомнить.${BASH_SOURCE[0]}
вместо того,$0
чтобы работать сsource my/script.sh
${BASH_SOURCE[0]}
не является удовлетворительным вообще.${BASH_SOURCE:-0}
намного лучше.Вы можете использовать
$BASH_SOURCE
:Обратите внимание, что вам нужно использовать,
#!/bin/bash
а не#!/bin/sh
потому, что это расширение Bash.источник
./foo/script
, то$(dirname $BASH_SOURCE)
есть./foo
.realpath
команду, чтобы получить полный путь ./foo/script. Такdirname $(realpath ./foo/script)
что даст путь сценария.Это должно сделать это:
Это работает с символическими ссылками и пробелами в пути.
Смотрите справочные страницы для
dirname
иreadlink
.Судя по комментариям, он не работает с Mac OS. Я понятия не имею, почему это так. Какие-либо предложения?
источник
./script.sh
показано,.
вместо полного пути к каталогуstat
вместо этого. Но тем не менее, это показывает,.
если вы находитесь в «этом» реж.coreutils
с Homebrew и использоватьgreadlink
для получения-f
опции на MacOS, потому что это * BSD под прикрытием, а не Linux.DIR="$(dirname "$(readlink -f "$0")")"
pwd
может использоваться для поиска текущего рабочего каталога иdirname
для поиска каталога определенного файла (команда, которая была выполнена, есть$0
, поэтомуdirname $0
должна предоставить каталог текущего сценария).Тем не менее,
dirname
дает именно часть каталога имени файла, которая, скорее всего, будет относительно текущего рабочего каталога. Если вашему сценарию по какой-либо причине необходимо изменить каталог, вывод из негоdirname
становится бессмысленным.Я предлагаю следующее:
Таким образом, вы получите абсолютный, а не относительный каталог.
Поскольку скрипт будет запускаться в отдельном экземпляре bash, нет необходимости впоследствии восстанавливать рабочий каталог, но если вы по какой-то причине захотите вернуться обратно в свой скрипт, вы можете легко присвоить значение
pwd
переменной перед вами изменить каталог, для будущего использования.Хотя просто
решает конкретный сценарий в вопросе, я нахожу имеющий абсолютный путь к более полезному в целом.
источник
dirname $0
&& pwd)Я устал приходить на эту страницу снова и снова, чтобы скопировать вставить одну строку в принятый ответ. Проблема в том, что это нелегко понять и запомнить.
Вот простой в запоминании скрипт:
источник
DIR=$(realpath "$(dirname "${BASH_SOURCE[0]}")")
realpath
«вручную» с цикломreadlink
? Даже наreadlink
страницеNote realpath(1) is the preferred command to use for canonicalization functionality.
realpath
раньшеdirname
, а не после? Если сам файл сценария является символической ссылкой ... Это даст что-то вродеDIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
. На самом деле очень близко к ответу, предложенному Саймоном.Я не думаю, что это так просто, как это сделали другие.
pwd
не работает, так как текущий каталог не обязательно является каталогом со скриптом.$0
тоже не всегда есть информация. Рассмотрим следующие три способа вызова скрипта:В первом и третьем способах
$0
нет полной информации о пути. Во втором и третьемpwd
не работает. Единственный способ получить каталог третьим способом - запустить путь и найти файл с правильным соответствием. В основном код должен был бы переделывать то, что делает ОС.Один из способов сделать то, что вы просите, - просто жестко закодировать данные в
/usr/share
каталоге и сослаться на них по полному пути. В/usr/bin
любом случае данные не должны находиться в каталоге, так что это, вероятно, то, что нужно сделать.источник
источник
$0
ниpwd
гарантированно иметь нужную информацию, в зависимости от того, как будет вызван скрипт.источник
$BASH_SOURCE
более$0
, потому что это явно даже для читателей не очень хорошо разбирающихся в Баш.$(dirname -- "$(readlink -f -- "$BASH_SOURCE")")
Это получает текущий рабочий каталог в Mac OS X 10.6.6:
источник
Это специфично для Linux, но вы можете использовать:
источник
/proc/fd/$$/255
кажется, указывает на tty, а не на каталог. Например, в моей текущей оболочке входа в систему все файловые дескрипторы 0, 1, 2 и 255 относятся к/dev/pts/4
. В любом случае, в руководстве по bash не упоминается fd 255. Поэтому, вероятно, неразумно зависеть от этого поведения. \realpath ${BASH_SOURCE[0]};
, казалось бы, лучший путь.Вот POSIX-совместимая строка:
источник
cd
настроен для печати нового пути.Я попробовал все это, и никто не работал. Один был очень близко, но имел крошечную ошибку, которая сильно его сломала; они забыли завернуть путь в кавычки.
Также многие люди предполагают, что вы запускаете скрипт из оболочки, поэтому они забывают, когда вы открываете новый скрипт, он по умолчанию у вас дома.
Попробуйте этот каталог для размера:
Это правильно, независимо от того, как и где вы запускаете:
Итак, чтобы сделать его действительно полезным, вот как перейти в каталог запущенного скрипта:
источник
ln -s ../bin64/foo /usr/bin/foo
).Вот простой, правильный способ:
Объяснение:
${BASH_SOURCE[0]}
- полный путь к сценарию. Значение этого параметра будет правильным, даже если сценарий получен, например,source <(echo 'echo $0')
печатает bash , а при его замене${BASH_SOURCE[0]}
будет напечатан полный путь сценария. (Конечно, это предполагает, что вы в порядке, принимая зависимость от Bash.)readlink -f
- Рекурсивно разрешает любые символические ссылки в указанном пути. Это расширение GNU, которое недоступно (например, в системах BSD). Если у вас Mac, вы можете использовать Homebrew для установки GNUcoreutils
и заменить его наgreadlink -f
.И, конечно,
dirname
получает родительский каталог пути.источник
greadlink -f
к сожалению, не работает эффективно приsource
написании сценария на Mac :(Самый короткий и самый элегантный способ сделать это:
Это будет работать на всех платформах и очень чисто.
Более подробную информацию можно найти в разделе «В каком каталоге находится этот bash-скрипт? ».
источник
Я бы использовал что-то вроде этого:
источник
sh
тоже! Проблема с простымиdirname "$0"
решениями: если скрипт находится в$PATH
и вызывается без пути, он даст неверный результат.PATH
,$0
будет содержать абсолютное имя файла. Если скрипт вызывается с относительным или абсолютным именем файла, содержащим/
,$0
будет содержать это.Это небольшой пересмотр решения e-sat, и 3bcdnlklvc04a указал в своем ответе :
Это должно работать во всех перечисленных случаях.
Это предотвратит
popd
неудачуpushd
, благодаря konsolebox.источник
SCRIPT_DIR=''; pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")" > /dev/null && { SCRIPT_DIR=$PWD; popd > /dev/null; }
popd
в случаях (даже в редких случаях), где происходитpushd
сбой. А в случаеpushd
неудачи, как вы думаете, какой должна быть ценностьSCRIPT_DIR
? Действие может варьироваться в зависимости от того, что может показаться логичным или того, что один пользователь может предпочесть, но, безусловно, делатьpopd
это неправильно.pushd
popd
опасностей можно избежать, просто отбросив их и используя вместо них знакcd
+,pwd
заключенный в подстановку команд.SCRIPT_DIR=$(...)
Для систем, имеющих GNU coreutils
readlink
(например, linux):Там нет необходимости использовать,
BASH_SOURCE
когда$0
содержит имя файла сценария.источник
dirname
колла. Необходим, если путь к каталогу содержит пробелы.источник
$0
не будет работать для исходного сценария$_
Стоит упомянуть в качестве альтернативы$0
. Если вы запускаете скрипт из Bash, принятый ответ может быть сокращен до:Обратите внимание, что это должно быть первым утверждением в вашем скрипте.
источник
source
или.
сценарий. В этих ситуациях$_
будет содержать последний параметр последней команды, которую вы выполнили перед.
.$BASH_SOURCE
работает каждый раз.Я сравнил многие ответы и дал несколько более компактных решений. Похоже, что они справляются со всеми безумными крайними случаями, возникающими из вашей любимой комбинации:
script
,bash script
,bash -c script
,source script
, или. script
Если вы работаете в Linux, кажется, что использование
proc
дескриптора - лучшее решение для поиска полностью разрешенного источника запущенного в данный момент скрипта (в интерактивном сеансе ссылка указывает на соответствующий/dev/pts/X
):Это немного уродливо, но исправление компактно и легко для понимания. Мы не используем только примитивы bash, но я согласен с этим, потому
readlink
что значительно упрощает задачу. Операторecho X
add добавляетX
в конец строки переменной, так что любые пробелы в имени файла не съедаются, а подстановка параметров${VAR%X}
в конце строки избавляется отX
. Так какreadlink
добавляет новую строку (которая обычно используется в подстановке команд, если бы не наш предыдущий трюк), мы также должны избавиться от этого. Это легче всего сделать с помощью$''
схемы цитирования, которая позволяет нам использовать escape-последовательности, такие как\n
представлять новые строки (это также, как вы можете легко создавать хитро названные каталоги и файлы).Вышеприведенное должно охватывать ваши потребности в поиске текущего запущенного скрипта в Linux, но если у вас нет
proc
файловой системы в вашем распоряжении, или если вы пытаетесь найти полностью разрешенный путь какого-либо другого файла, то, возможно, вам найти приведенный ниже код полезным. Это всего лишь небольшая модификация вышеупомянутой однострочной. Если вы играете со странными каталогами / именами файлов, проверьте вывод с помощью обоихls
иreadlink
информативно, так какls
выведет «упрощенные» пути, заменяя?
такие вещи, как переводы строк.источник
/dev/pts/30
с bash на Ubuntu 14.10 Desktop.echo $resolved
я сохранил его какd
,chmod +x d
,./d
.#!/bin/bash
Попробуйте использовать:
источник
$0
для${BASH_SOURCE[0]}
так что этот способ будет работать в любом месте, в том числе и в функции.dirname
потому что последняя часть$0
может быть символической ссылкой, указывающей на файл, который не находится в том же каталоге, что и сама символическая ссылка. Решение, описанное в этом ответе, просто получает путь к каталогу, в котором хранится символическая ссылка, а не каталог цели. Кроме того, в этом решении отсутствует цитирование. Это не будет работать, если путь содержит специальные символы.dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"
Попробуйте следующее кросс-совместимое решение:
поскольку такие команды, как
realpath
илиreadlink
могут быть недоступны (в зависимости от операционной системы).Примечание: в Bash рекомендуется использовать
${BASH_SOURCE[0]}
вместо$0
, в противном случае путь может сломаться при поиске файла (source
/.
).В качестве альтернативы вы можете попробовать следующую функцию в bash:
Эта функция принимает 1 аргумент. Если аргумент уже имеет абсолютный путь, выведите его как есть, в противном случае выведите
$PWD
переменную + аргумент имени файла (без./
префикса).Связанные с:
источник
realpath
Функция @Chris принимает 1 аргумент. Если аргумент уже имеет абсолютный путь, выведите его как есть, в противном случае напечатайте$PWD
+ имя файла (без./
префикса).Я верю, что у меня есть это. Я опаздываю на вечеринку, но я думаю, что некоторые оценят, что они здесь, если встретят эту тему. Комментарии должны объяснить:
источник
Вот краткие способы получения информации о скрипте:
Папки и файлы:
Используя эти команды:
И я получил этот вывод:
Также смотрите: https://pastebin.com/J8KjxrPF
источник
Это работает в Bash-3.2:
Если у вас есть
~/bin
каталог в вашем$PATH
, у вас естьA
внутри этого каталога. Это источники сценария~/bin/lib/B
. Вы знаете, где включенный сценарий относительно исходного вlib
подкаталоге, а не где он находится относительно текущего каталога пользователя.Это решается следующим (внутри
A
):Неважно, где пользователь или как он вызывает скрипт, это всегда будет работать.
источник
which
очень спорно.type
,hash
И другие встроенные команды делают то же самое лучше в Баш.which
является более переносимым, хотя на самом деле это не то же самое, чтоwhich
используется в других оболочках, таких как tcsh, в которых он встроен.which
будучи внешним инструментом, у вас нет оснований полагать, что он ведет себя идентично родительской оболочке.Лучшее компактное решение, на мой взгляд, будет:
Там нет опоры ни на что, кроме Bash. Использование
dirname
,readlink
иbasename
в конечном итоге привести к проблемам с совместимостью, поэтому они лучше избегать , если это вообще возможно.источник
"$( cd "$( echo "${BASH_SOURCE[0]%/*}/" )"; pwd )"
. У вас будут проблемы с корневым каталогом, если вы этого не сделаете. Кроме того, почему вы даже должны использовать эхо?dirname
иbasename
POSIX стандартизированы, так почему бы не использовать их? Ссылки:dirname
,basename