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

Основной ответ: допустимые 5. или 5, входы

этот код обрабатывает его (но в моем примере отрицательные числа запрещены):

/^[0-9]+([.,][0-9]{1,2})?$/;

результаты приведены ниже:

true => "0" / true => "0.00" / true => "0.0" / true => "0,00" / true => "0,0" / true => "1,2" true => "1.1" / true => "1" / true => "100" true => "100.00" / true => "100.0" / true => "1.11" / true = > "1,11" / false => "-5" / false => "-0.00" / true => "101" / false => "0.00.0" / true => "0.000" / true => " 000.25 "/ false =>" .25 "/ true =>" 100.01 "/ true =>" 100.2 "/ true =>" 00 "/ false =>" 5. " / false => "6," / true => "82" / true => "81,3" / true => "7" / true => "7.654"

4530
задан 14 revs, 12 users 25% 1 February 2019 в 20:02
поделиться

23 ответа

#!/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'
6041
ответ дан 24 revs, 18 users 34% 1 February 2019 в 20:02
поделиться
  • 1
    @quellish: Они can' t быть вложенным, потому что they' ре от различных персистентных координаторов хранилища: This means that we need two separate NSPersistentStoreCoordinators, each of them having it's own NSManagedObjectContext. – Arek Holko 14 October 2013 в 07:31

Использовать dirname "$0":

#!/bin/bash
echo "The script you are running has basename `basename "$0"`, dirname `dirname "$0"`"
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
823
ответ дан 4 revs, 4 users 77% 1 February 2019 в 20:02
поделиться
  • 1
    Он ясно хочет использовать энергию, не (отличающийся?) IDE. – Limited Atonement 28 March 2013 в 14:55

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

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

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

#!/bin/bash

reldir=`dirname $0`
cd $reldir
directory=`pwd`

echo "Directory is $directory"

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

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

Хотя просто

cd `dirname $0`

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

60
ответ дан 3 revs, 2 users 94% 1 February 2019 в 20:02
поделиться
  • 1
    Вы могли бы хотеть инвестировать время во Внешнее Вспомогательное платформа, выпущенная с 3,0 – Andrei Tanasescu 30 June 2009 в 20:21

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

./script

/usr/bin/script

script

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

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

34
ответ дан 2 revs, 2 users 83%Jim 1 February 2019 в 20:02
поделиться
  • 1
    Да, я хочу найти все bluetooth-устройства в диапазоне и отправить данные назад и вперед. На основе документации Apple кажется, что можно только соединиться с другими iPhone, но you' ре говоря это может автообнаружить другие устройства. Это верно? – Tai Squared 30 June 2009 в 21:00
#!/bin/sh
PRG="$0"

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

scriptdir=`dirname "$PRG"`
13
ответ дан Monkeyboy 1 February 2019 в 20:02
поделиться

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

#!/bin/bash

scriptdir=`dirname "$BASH_SOURCE"`

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

97
ответ дан 2 revs 1 February 2019 в 20:02
поделиться
  • 1
    Извините за многие вопросы - базовой проблемой является банка подключение iPhone к произвольному устройству. Например, если бы приложение для чтения электрических счетчиков, я хотел бы иметь возможность идти в комнату и подключение к любому данному метру, ничего не зная об определенном метре (идентификатор Bluetooth, IP-адрес, и т.д.). Кажется, что это было бы возможно с Добрый день (если бы метры поддерживали протокол), но не Bluetooth. Это корректно? Для подключения с другим Добрый день устройства iPhone должен был бы быть быть в беспроводной сети или подключен через Bluetooth? Это doesn' t кажутся так. – Tai Squared 30 June 2009 в 19:56

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

path="$( dirname "$( which "$0" )" )"

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

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

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

source "$( dirname "$( which "$0" )" )/lib/B"

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

7
ответ дан 5 revs, 2 users 97% 1 February 2019 в 20:02
поделиться

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

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

для меня.

7
ответ дан 2 revs, 2 users 86% 1 February 2019 в 20:02
поделиться

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

LIBDIR=$(dirname "$(readlink -f "$(type -P $0 || echo $0)")")
source $LIBDIR/lib.sh
0
ответ дан 2 revsTokland 1 February 2019 в 20:02
поделиться

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

SELF=$(readlink /proc/$/fd/255)
26
ответ дан 3 revs, 3 users 75% 1 February 2019 в 20:02
поделиться

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

`dirname $0`

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

$(dirname "$0")
105
ответ дан 7 revs, 7 users 37% 1 February 2019 в 20:02
поделиться
  • 1
    Нет, iPhone doesn' t должны быть в сети Wi-Fi: это будет использовать любой сетевое устройство, доступное в системе - в особенности: Bluetooth. Для iOS6 вперед, Apple отключает поиск BT для Добрый день по умолчанию (Apple' s объяснение (оправдание) за то, что сделали это изменение повреждения и официальные инструкции по обходному решению developer.apple.com/library/ios/qa/qa1753/_index.html#//… ) – Adam 24 October 2013 в 15: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

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

  • при вызове через multple гибкую ссылку глубины,
  • когда файл это
  • когда сценарий, названный командой"source"иначе . (точечный) оператор.
  • когда аргумент $0 изменяется от вызывающей стороны.
  • "./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
ответ дан 9 revs, 7 users 54% 2 February 2019 в 06:02
поделиться
  • 1
    Добрый день просто протокол обнаружения, таким образом, его диапазон что Ваш network' s диапазон. Это предназначается для использования в локальной сети, так, чтобы в значительной степени означал, что iPhone должен быть в сети WiFi. Сами устройства могли быть предрасположены или быть подключены к сети другими средствами, все же. – Brad Larson♦ 1 July 2009 в 23:33

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

cd $(dirname $(which $0) )

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

DIR=$(/usr/bin/pwd)
-2
ответ дан 2 revs, 2 users 62%Robert J 2 February 2019 в 06:02
поделиться

Можно сделать это просто объединение названия сценария ([112]) с realpath и/или dirname. Это работает на Bash и Shell.

#!/usr/bin/env bash

RELATIVE_PATH="[110]"
RELATIVE_DIR_PATH="$(dirname "[110]")"
FULL_DIR_PATH="$(realpath "[110]" | xargs dirname)"
FULL_PATH="$(realpath "[110]")"

echo "RELATIVE_PATH->${RELATIVE_PATH}<-"
echo "RELATIVE_DIR_PATH->${RELATIVE_DIR_PATH}<-"
echo "FULL_DIR_PATH->${FULL_DIR_PATH}<-"
echo "FULL_PATH->${FULL_PATH}<-"

вывод будет чем-то вроде этого:

# RELATIVE_PATH->./bin/startup.sh<-
# RELATIVE_DIR_PATH->./bin<-
# FULL_DIR_PATH->/opt/my_app/bin<-
# FULL_PATH->/opt/my_app/bin/startup.sh<-

0$ название самого сценария

https://www.tldp.org/LDP/abs/html/othertypesv.html

пример: https://gist.github.com/LozanoMatheus/da96b4e44b89b13ad4af10ac4602ad99

4
ответ дан Matheus Lozano 14 September 2019 в 15:50
поделиться

Это - то, что я обработал в течение лет для использования в качестве заголовка на моих сценариях удара:

## BASE BRAIN - Get where you're from and who you are.
MYPID=$
ORIGINAL_DIR="$(pwd)" # This is not a hot air balloon ride..
fa="[110]" # First Assumption
ta= # Temporary Assumption
wa= # Weighed Assumption
while true; do
    [ "${fa:0:1}" = "/" ] && wa=[110] && break
    [ "${fa:0:2}" = "./" ] && ta="${ORIGINAL_DIR}/${fa:2}" && [ -e "$ta" ] && wa="$ta" && break
    ta="${ORIGINAL_DIR}/${fa}" && [ -e "$ta" ] && wa="$ta" && break
done
SW="$wa"
SWDIR="$(dirname "$wa")"
SWBIN="$(basename "$wa")"
unset ta fa wa
( [ ! -e "$SWDIR/$SWBIN" ] || [ -z "$SW" ] ) && echo "I could not find my way around :( possible bug in the TOP script" && exit 1

в этой точке Ваш SW переменных SWDIR и SWBIN содержат то, в чем Вы нуждаетесь.

0
ответ дан MatteoBee 14 September 2019 в 15:50
поделиться

Команда dirname является самой простой, просто анализируя путь до имени файла из Переменная $ 0 (имя сценария):

dirname "$0"

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

Некоторые другие упоминали команду readlink , но в самом простом случае вы можете использовать:

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

readlink преобразует путь скрипта в абсолютный путь от корня файловой системы. Таким образом, любые пути, содержащие одинарные или двойные точки, тильды и / или символические ссылки, будут преобразованы в полный путь.

Вот сценарий, демонстрирующий каждый из них, whatdir.sh:

#!/bin/bash
echo "pwd: `pwd`"
echo "\$0: $0"
echo "basename: `basename $0`"
echo "dirname: `dirname $0`"
echo "dirname/readlink: $(dirname $(readlink -f $0))"

Запуск этого сценария в моем home dir, используя относительный путь:

>>>$ ./whatdir.sh 
pwd: /Users/phatblat
$0: ./whatdir.sh
basename: whatdir.sh
dirname: .
dirname/readlink: /Users/phatblat

Опять же, но используя полный путь к сценарию:

>>>$ /Users/phatblat/whatdir.sh 
pwd: /Users/phatblat
$0: /Users/phatblat/whatdir.sh
basename: whatdir.sh
dirname: /Users/phatblat
dirname/readlink: /Users/phatblat

Теперь меняем каталоги:

>>>$ cd /tmp
>>>$ ~/whatdir.sh 
pwd: /tmp
$0: /Users/phatblat/whatdir.sh
basename: whatdir.sh
dirname: /Users/phatblat
dirname/readlink: /Users/phatblat

И, наконец, используя символическую ссылку для выполнения сценария:

>>>$ ln -s ~/whatdir.sh whatdirlink.sh
>>>$ ./whatdirlink.sh 
pwd: /tmp
$0: ./whatdirlink.sh
basename: whatdirlink.sh
dirname: .
dirname/readlink: /Users/phatblat
463
ответ дан 22 November 2019 в 19:37
поделиться

Небольшая доработка решения e-satis и 3bcdnlklvc04a указали в их ответ

SCRIPT_DIR=''
pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")" > /dev/null && {
    SCRIPT_DIR="$PWD"
    popd > /dev/null
}    

. Это должно работать во всех перечисленных ими случаях.

РЕДАКТИРОВАТЬ: запретить popd после неудачного pushd, благодаря konsolebox

14
ответ дан 22 November 2019 в 19:37
поделиться

Это единственный способ, который я нашел, чтобы сказать надежно:

SCRIPT_DIR=$(dirname $(cd "$(dirname "$BASH_SOURCE")"; pwd))
4
ответ дан 22 November 2019 в 19:37
поделиться

Я хочу прокомментировать предыдущий ответ там ( https://stackoverflow.com/a/201915/5010054), но не имею достаточной репутации, чтобы сделать это.

Найденный решением для этого два года назад на сайте документации яблока: https://developer.apple.com/library/archive/documentation/OpenSource/Conceptual/ShellScripting/AdvancedTechniques/AdvancedTechniques.html . И я придерживался этого метода впоследствии. Это не может обработать гибкую ссылку, но иначе работает вполне прилично на меня. Я отправляю его здесь для любого, кому нужен он и как запрос комментария.

#!/bin/sh

# Get an absolute path for the poem.txt file.
POEM="$PWD/../poem.txt"

# Get an absolute path for the script file.
SCRIPT="$(which [110])"
if [ "x$(echo $SCRIPT | grep '^\/')" = "x" ] ; then
    SCRIPT="$PWD/$SCRIPT"
fi

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

0
ответ дан 22 November 2019 в 19:37
поделиться

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

, поскольку у меня были проблемы с BASH_SOURCE с включенным подходом 'CD' к некоторым очень новым и также к менее новой установленной Ubuntu, Гостеприимной (16.04) системы при вызове сценария оболочки посредством "sh my_script.sh", я испытал что-то другое, что на данный момент, кажется, работает вполне гладко за моими целями. Подход немного более компактен в сценарии и является дальнейшим намного меньшим загадочным чувством.

этот альтернативный подход использует внешние приложения 'realpath' и ''dirname от coreutils пакета. (хорошо, не любому нравятся издержки вызова вторичного processe - но видя, что сценарии мультилинии для разрешения истинного объекта это привычка, что плохо любой имеющий его решает в единственном двоичном использовании.)

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

SCRIPT=`realpath -s [110]`
SCRIPTPATH=`dirname $SCRIPT`

Или при наличии шанса использования путей с пробелами (или возможно другие специальные символы):

SCRIPT=`realpath -s "[111]"`
SCRIPTPATH=`dirname "$SCRIPT"`

действительно, если Вам не нужно значение переменной СЦЕНАРИЯ затем, Вы смогли объединять это с двумя лайнерами даже в одну строку. но почему действительно необходимо потратить усилие для этого?

0
ответ дан 22 November 2019 в 19:37
поделиться

Следующее возвратит текущий каталог работ сценария

  • , если это будет получено или не получит
  • работы, если выполнено в текущем каталоге или некотором другом каталоге.
  • работы, если относительные каталоги используются.
  • работы с ударом, не уверенным в других оболочках.
/tmp/a/b/c $ . ./test.sh
/tmp/a/b/c

/tmp/a/b/c $ . /tmp/a/b/c/test.sh
/tmp/a/b/c

/tmp/a/b/c $ ./test.sh
/tmp/a/b/c

/tmp/a/b/c $ /tmp/a/b/c/test.sh
/tmp/a/b/c

/tmp/a/b/c $ cd

~ $ . /tmp/a/b/c/test.sh
/tmp/a/b/c

~ $ . ../../tmp/a/b/c/test.sh
/tmp/a/b/c

~ $ /tmp/a/b/c/test.sh
/tmp/a/b/c

~ $ ../../tmp/a/b/c/test.sh
/tmp/a/b/c

test.sh

#!/usr/bin/env bash

# snagged from: https://stackoverflow.com/a/51264222/26510
function toAbsPath {
    local target
    target="$1"

    if [ "$target" == "." ]; then
        echo "$(pwd)"
    elif [ "$target" == ".." ]; then
        echo "$(dirname "$(pwd)")"
    else
        echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
    fi
}

function getScriptDir(){
  local SOURCED
  local RESULT
  (return 0 2>/dev/null) && SOURCED=1 || SOURCED=0

  if [ "$SOURCED" == "1" ]
  then
    RESULT=$(dirname "$1")
  else
    RESULT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
  fi
  toAbsPath "$RESULT"
}

SCRIPT_DIR=$(getScriptDir "[111]")
echo "$SCRIPT_DIR"
0
ответ дан 22 November 2019 в 19:37
поделиться
ME=`type -p $0`
MDIR="${ME%/*}"
WORK_DIR=$(cd $MDIR && pwd)
-2
ответ дан 22 November 2019 в 19:37
поделиться
function getScriptAbsoluteDir { # fold>>
    # @description used to get the script path
    # @param $1 the script $0 parameter
    local script_invoke_path="$1"
    local cwd=`pwd`

    # absolute path ? if so, the first character is a /
    if test "x${script_invoke_path:0:1}" = 'x/'
    then
        RESULT=`dirname "$script_invoke_path"`
    else
        RESULT=`dirname "$cwd/$script_invoke_path"`
    fi
} # <<fold
-1
ответ дан 22 November 2019 в 19:37
поделиться
Другие вопросы по тегам:

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