Получить исходный каталог скрипта Bash из самого скрипта

Как получить путь к каталогу, в котором находится скрипт Bash , внутри этого скрипта?

Например, скажем, я хочу используйте скрипт Bash в качестве средства запуска для другого приложения. Я хочу изменить рабочий каталог на тот, где находится скрипт Bash, чтобы я мог работать с файлами в этом каталоге, например так:

$ ./application

4591
задан 02.02.2019, 08:02

13 ответов

#!/bin/bash

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

полезная острота, которая даст Вам полное имя каталога сценария, неважно, откуда это называют.

Это будет работать пока последний компонент пути, используемого, чтобы найти, что сценарий не является символьной ссылкой (ссылки каталога в порядке). Если Вы также хотите разрешить какие-либо ссылки на сам сценарий, Вам нужно многострочное решение:

#!/bin/bash

SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
  DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
  SOURCE="$(readlink "$SOURCE")"
  [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"

Этот последний будет работать с любой комбинацией псевдонимов, source, bash -c, символьные ссылки, и т.д.

Остерегаются: если Вы cd к различному каталогу прежде, чем выполнить этот отрывок, результат может быть неправильным!

кроме того, не упустите $CDPATH глюки , и выходные побочные эффекты stderr, если пользователь энергично переопределил CD для перенаправления вывода к stderr вместо этого (включая escape-последовательности, такой, звоня update_terminal_cwd >&2 на Mac). При добавлении >/dev/null 2>&1 в конце Вашего cd команда будет заботиться об обеих возможностях.

, Чтобы понять, как это работает, попытайтесь выполнить это больше подробной формы:

#!/bin/bash

SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
  TARGET="$(readlink "$SOURCE")"
  if [[ $TARGET == /* ]]; then
    echo "SOURCE '$SOURCE' is an absolute symlink to '$TARGET'"
    SOURCE="$TARGET"
  else
    DIR="$( dirname "$SOURCE" )"
    echo "SOURCE '$SOURCE' is a relative symlink to '$TARGET' (relative to '$DIR')"
    SOURCE="$DIR/$TARGET" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
  fi
done
echo "SOURCE is '$SOURCE'"
RDIR="$( dirname "$SOURCE" )"
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
if [ "$DIR" != "$RDIR" ]; then
  echo "DIR '$RDIR' resolves to '$DIR'"
fi
echo "DIR is '$DIR'"

И это распечатает что-то как:

SOURCE './scriptdir.sh' is a relative symlink to 'sym2/scriptdir.sh' (relative to '.')
SOURCE is './sym2/scriptdir.sh'
DIR './sym2' resolves to '/home/ubuntu/dotfiles/fo fo/real/real1/real2'
DIR is '/home/ubuntu/dotfiles/fo fo/real/real1/real2'
6082
ответ дан 04.10.2019, 09:58
  • 1
    Можно плавить этот подход с ответом user25866, чтобы найти решение, которое работает с source <script> и bash <script>: DIR="$(cd -P "$(dirname "${BASH_SOURCE[0]}")" && pwd)". – Dan Moulding 20.10.2011, 05:54
  • 2
    Обратите внимание, что BASH_SOURCE был добавлен для отладки целей в версии bash-3.0-alpha. Таким образом, если Вы работаете с унаследованной системой этот won' t работа. – JeffCharter 12.01.2013, 12:12
  • 3
    Иногда cd печать что-то к STDOUT! Например, если Ваш $CDPATH имеет .. Для покрытия этого случая используйте DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )" – user716468 03.02.2013, 15:33
  • 4
    @quellish: Они can' t быть вложенным, потому что they' ре от различных персистентных координаторов хранилища: This means that we need two separate NSPersistentStoreCoordinators, each of them having it's own NSManagedObjectContext. – Arek Holko 14.10.2013, 10:31

Я обычно делаю:

LIBDIR=$(dirname "$(readlink -f "$(type -P [110] || echo [110])")")
source $LIBDIR/lib.sh
0
ответ дан 14.09.2019, 18:50

Я хочу удостовериться, что сценарий работает в его каталоге. Так

cd $(dirname $(which [110]) )

После этого если Вы действительно хотите знать, куда Вы работают затем, выполняет команду ниже.

DIR=$(/usr/bin/pwd)
-2
ответ дан 14.09.2019, 18:50

Используйте dirname "[112]":

#!/bin/bash
echo "The script you are running has basename `basename "[110]"`, dirname `dirname "[110]"`"
echo "The present working directory is `pwd`"

использование pwd один не будет работать, если Вы не выполните сценарий из каталога, это содержится в.

[matt@server1 ~]$ pwd
/home/matt
[matt@server1 ~]$ ./test2.sh
The script you are running has basename test2.sh, dirname .
The present working directory is /home/matt
[matt@server1 ~]$ cd /tmp
[matt@server1 tmp]$ ~/test2.sh
The script you are running has basename test2.sh, dirname /home/matt
The present working directory is /tmp
803
ответ дан 04.10.2019, 09:58
  • 1
    Он ясно хочет использовать энергию, не (отличающийся?) IDE. – Limited Atonement 28.03.2013, 16:55

Короткий ответ:

`dirname [110]`

или ( предпочтительно ):

$(dirname "[111]")
105
ответ дан 04.10.2019, 09:58
  • 1
    Нет, iPhone doesn' t должны быть в сети Wi-Fi: это будет использовать любой сетевое устройство, доступное в системе - в особенности: Bluetooth. Для iOS6 вперед, Apple отключает поиск BT для Добрый день по умолчанию (Apple' s объяснение (оправдание) за то, что сделали это изменение повреждения и официальные инструкции по обходному решению developer.apple.com/library/ios/qa/qa1753/_index.html#//… ) – Adam 24.10.2013, 18:17
pushd . > /dev/null
SCRIPT_PATH="${BASH_SOURCE[0]}"
if ([ -h "${SCRIPT_PATH}" ]); then
  while([ -h "${SCRIPT_PATH}" ]); do cd `dirname "$SCRIPT_PATH"`; 
  SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done
fi
cd `dirname ${SCRIPT_PATH}` > /dev/null
SCRIPT_PATH=`pwd`;
popd  > /dev/null

Работы для всех версий, включая [1 125]

  • при вызове через multple гибкую ссылку глубины,
  • когда файл это
  • когда сценарий, названный командой "112" иначе . (точечный) оператор.
  • , когда аргумент [114] изменяется от вызывающей стороны.
  • "./script"
  • "/full/path/to/script"
  • "/some/path/../../another/path/script"
  • "./some/folder/script"

, С другой стороны, если сам сценарий удара относительная символьная ссылка , Вы хотите следовать за ним и возвратить полный путь связанного - к сценарию:

pushd . > /dev/null
SCRIPT_PATH="${BASH_SOURCE[0]}";
if ([ -h "${SCRIPT_PATH}" ]) then
  while([ -h "${SCRIPT_PATH}" ]) do cd `dirname "$SCRIPT_PATH"`; SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done
fi
cd `dirname ${SCRIPT_PATH}` > /dev/null
SCRIPT_PATH=`pwd`;
popd  > /dev/null

SCRIPT_PATH дан в полном пути, неважно, как это называют.
Просто удостоверяются, что Вы определяете местоположение этого в начале сценария.

Этот Копилефт комментария и кода, выбираемая лицензия под GPL2.0 или позже или CC-SA 3.0 (Доля CreativeCommons Одинаково) или позже. (c) 2008.Все права защищены. Никакая гарантия любого вида. Вас предупредили.
http://www.gnu.org/licenses/gpl-2.0.txt
http://creativecommons.org/licenses/by-sa/3.0/
18eedfe1c99df68dc94d4a94712a71aaa8e1e9e36cacf421b9463dd2bbaa02906d0d6656

179
ответ дан 04.10.2019, 09:58
  • 1
    Добрый день просто протокол обнаружения, таким образом, его диапазон что Ваш network' s диапазон. Это предназначается для использования в локальной сети, так, чтобы в значительной степени означал, что iPhone должен быть в сети WiFi. Сами устройства могли быть предрасположены или быть подключены к сети другими средствами, все же. – Brad Larson♦ 01.07.2009, 15:33

Можно использовать $BASH_SOURCE

#!/bin/bash

scriptdir=`dirname "$BASH_SOURCE"`

Примечание, что необходимо использовать #!/bin/bash и не #!/bin/sh, так как это - расширение удара

99
ответ дан 04.10.2019, 09:58
  • 1
    Извините за многие вопросы - базовой проблемой является банка подключение iPhone к произвольному устройству. Например, если бы приложение для чтения электрических счетчиков, я хотел бы иметь возможность идти в комнату и подключение к любому данному метру, ничего не зная об определенном метре (идентификатор Bluetooth, IP-адрес, и т.д.). Кажется, что это было бы возможно с Добрый день (если бы метры поддерживали протокол), но не Bluetooth. Это корректно? Для подключения с другим Добрый день устройства iPhone должен был бы быть быть в беспроводной сети или подключен через Bluetooth? Это doesn' t кажутся так. – Tai Squared 30.06.2009, 22:56
  • 2
    Когда я делаю ./foo/script, тогда $(dirname $BASH_SOURCE) ./foo. – Till 26.10.2010, 07:06
  • 3
    также работы с источником/. оператор! – grosser 12.08.2011, 10:53

Это - конкретный Linux, но Вы могли использовать:

SELF=$(readlink /proc/$/fd/255)
27
ответ дан 04.10.2019, 09:58

pwd может использоваться, чтобы найти, что текущий рабочий каталог, и dirname находит каталог конкретного файла (команда, которая была выполнена, [114], таким образом dirname [115] должен дать Вам каталог текущего сценария).

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

я предлагаю следующее:

#!/bin/bash

reldir=`dirname [110]`
cd $reldir
directory=`pwd`

echo "Directory is $directory"

Таким образом, Вы получаете абсолют, скорее тогда относительный каталог.

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

, Хотя всего

cd `dirname [111]`

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

58
ответ дан 04.10.2019, 09:58
  • 1
    Вы могли бы хотеть инвестировать время во Внешнее Вспомогательное платформа, выпущенная с 3,0 – Andrei Tanasescu 30.06.2009, 23:21

Я не думаю, что это столь легко, как другие разобрали его, чтобы быть. pwd не работает, поскольку текущий dir является не обязательно каталогом со сценарием. 0$ не всегда имеют информацию также. Рассмотрите следующие три способа вызвать сценарий.

./script

/usr/bin/script

script

первыми и третьими способами 0$ не имеют информации о полном пути Во втором, и третье, pwd не работают. Единственный способ получить dir третьим путем состоял бы в том, чтобы пробежать путь и найти файл с корректным соответствием. В основном код должен был бы восстановить то, что делает ОС.

Один способ сделать, что Вы спрашиваете, был бы только к hardcode данные в/usr/share dir и сослался бы на него полным путем. Данные shoudn't быть в/usr/bin dir так или иначе, таким образом, это, вероятно, нужно.

36
ответ дан 04.10.2019, 09:58
  • 1
    Да, я хочу найти все bluetooth-устройства в диапазоне и отправить данные назад и вперед. На основе документации Apple кажется, что можно только соединиться с другими iPhone, но you' ре говоря это может автообнаружить другие устройства. Это верно? – Tai Squared 01.07.2009, 00:00
#!/bin/sh
PRG="[110]"

# need this for relative symlinks
while [ -h "$PRG" ] ; do
   PRG=`readlink "$PRG"`
done

scriptdir=`dirname "$PRG"`
13
ответ дан 04.10.2019, 09:58

Это работает в ударе 3.2:

path="$( dirname "$( which "[110]" )" )"

Вот пример его использования:

Говорят, что Вы имеете ~ / мусорное ведро каталог, который находится в Вашем $PATH . У Вас есть сценарий внутренняя часть этот каталог. Это источник сценарий ~/bin/lib/b с. Вы знаете, где включенный сценарий относительно исходного (подкаталог lib ), но не, где это относительно текущего каталога пользователя.

Это решено следующим (в А ):

source "$( dirname "$( which "[111]" )" )/lib/B"

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

7
ответ дан 04.10.2019, 09:58

Хм, если в базовом имени пути & dirname просто не собираются сокращать его и идут, путь тверд (что, если родитель не экспортировал ПУТЬ!). Однако оболочка должна иметь открытый дескриптор к своему сценарию, и в ударе дескриптор является работами № 255.

SELF=`readlink /proc/$/fd/255`

для меня.

7
ответ дан 04.10.2019, 09:58

Теги

Похожие вопросы