Найти абсолютный путь из скрипта

10

В сценарии я получаю $0возможный относительный путь к нему. Для преобразования в абсолют я нашел такое решение, которое не понимаю:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

Моя проблема в магии внутри ${0%/*}и ${0##*/}. Похоже, что первый извлекает имя каталога, а второй извлекает имя файла, я просто не понимаю, как.

maaartinus
источник
2
Это использует расширение параметров, но у меня это не сработало. Если ваш сценарий будет использоваться только в Linux, вы можете использовать, readlink -f $0чтобы получить канонический путь.
Шон Дж. Гофф
1
@Shawn: 1 голос за отличный комментарий, потому что вы правильно представили: «Это использует расширение параметров, но у меня это не сработало». dirnameUtil полезно здесь.
D4RIO
mywiki.wooledge.org/BashFAQ/028 и cyberciti.biz/faq/… говорят, BASH_SOURCEчто лучше, чем $0, поскольку $0дает набранную пользователем команду, которая может быть не выполняемым в данный момент скриптом.
Джоэл Пурра

Ответы:

8

Определения:

${string%substring} удаляет $substringсамое короткое совпадение с конца $string.

${string##substring}удаляет самое длинное совпадение $substringс начала $string.

Ваш пример:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

${0%/*} удаляет все после последней косой черты, давая вам имя каталога скрипта (который может быть относительным путем).

${0##*/} удаляет все до последней косой черты, давая вам только имя сценария.

Таким образом, эта команда переходит в каталог скрипта и объединяет текущий рабочий каталог (заданный $PWD) и имя скрипта, указывающее абсолютный путь.

Чтобы увидеть, что происходит, попробуйте:

echo ${0%/*}
echo ${0##*/}
кендырь
источник
Добавьте двойные кавычки вокруг всех расширений переменных, чтобы справиться с (почти всеми) именами файлов, содержащими специальные символы оболочки.
Жиль "ТАК - перестань быть злым"
10

Шон имел самое простое решение: readlink -f $0. Если вы хотите быть абсолютно уверенным в обработке странных имен файлов, вы можете использовать это:

absolute_path_x="$(readlink -fn -- "$0"; echo x)"
absolute_path="${absolute_path_x%x}"

Документация

l0b0
источник
1
Приятно видеть, что финальные символы новой строки правильно обработаны. К сожалению, readlink -fnэто специфично для Linux, NetBSD и OpenBSD.
Жиль "ТАК - перестань быть злым"
4

Вот более безопасный и понятный способ сделать эту работу:

abspath=$(unset CDPATH && cd "$(dirname "$0")" && echo $PWD/$(basename "$0"))

Заметки:

  • Если $0это пустое имя файла без предшествующего пути, исходный скрипт потерпит неудачу, но приведенный здесь будет работать. (Не проблема, $0но может быть в других приложениях.)
  • Любой подход потерпит неудачу, если путь к файлу на самом деле не существует. (Не проблема $0, но может быть в других приложениях.)
  • Это unsetважно, если ваш пользователь мог CDPATHустановить.
  • В отличие от readlink -fили realpath, это будет работать на не-Linux версиях Unix (например, Mac OS X).
Матиас Фрипп
источник
2

Если вы хотите изучить Расширение параметров оболочки, вы можете прочитать его здесь , но Расширение не всегда является хорошим выбором. В этом случае почти каждая Unix-подобная система имеет 2 полезных утилиты:

basename
dirname

Первый извлечет имя файла, а второй извлечет путь, поэтому, если у вас есть $ 0, скажите:

dirname $0

И вы получите путь.

ура

D4RIO
источник
dirname может возвращать относительные пути
opticyclic
0

Представляем pwd, встроенную в bash. Также находится в пакете GNU coreutils.

$ sh ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
$0: ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
cheeky binary from /home/jaroslav/tmp (/home/jaroslav/tmp)

$ cat /home/jaroslav/tmp/somewhere.sh

abs=$( cd `dirname "$0"` ; pwd -P)
absBin=$( cd `dirname "$0"` ; /bin/pwd -P)
echo \$0: $0
echo cheeky binary from $abs \($absBin\)
Ярослав Рахматуллин
источник