Как я могу получить абсолютное имя файла в сценарии оболочки в Mac OS X?

19

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

В Linux это, кажется, делается так:

$(readlink -mn "$0")

но, readlinkпохоже, работает совсем по- другому на Mac OS X.

Я читал, что это делается с помощью

$(realpath $0)

в BSD, но это тоже не работает. Mac OS X не имеет realpath.

Любая идея?

Huxi
источник
1
Смотрите этот вопрос на SO: stackoverflow.com/questions/799679/…
Telemachus
3
И вот этот: stackoverflow.com/questions/1055671/…
Telemachus
Еще больше возможностей: stackoverflow.com/questions/7665/…
Герхард Бургер

Ответы:

19

Я обманываю и использую Perl для этой вещи:

#!/bin/bash
dirname=`perl -e 'use Cwd "abs_path";print abs_path(shift)' $0`
echo $dirname

Вы бы подумали, что я просто напишу весь скрипт на Perl, и часто я делаю, но не всегда.

ericslaw
источник
Это работает, спасибо большое. Я дам вам голос, как только смогу. У кого-нибудь есть способ "чистой оболочки" сделать это?
Хуси
1
Боюсь, это так же хорошо, как и получается. (Учитывая множество многострочных хаков «чистой оболочки», которые можно найти в Google.)
Arjan
другая возможность (хотя и уродливая) - пройти путь «..», запоминая (через рекурсию или массив), пока «..» не вернет тот же файл, который вы только что имели (то есть: вы находитесь наверху), а затем вернитесь к сборке путь, как вы идете. Я видел, что ПО для резервного копирования Networker от Legato делает это во время strace как метод получения «истинного» пути (но, возможно, не абсолютного). Но это было бы намного больше кода, чем выше.
ericslaw
Не уверен, почему кто-то изменил код, чтобы использовать $ 1 вместо $ 0. Разве $ 1 не первый аргумент сценария bash? Я хотел путь к исполняемому скрипту bash, а не его первый аргумент.
ericslaw
27
#!/usr/bin/env bash
scriptDir="$(cd "$(dirname "$0")" && pwd -P)"
jhclark
источник
Работает в MacOSX тоже.
Алексар
1
Это супер! Есть много других слишком сложных ответов.
Джейсон С
3
Это работает только для файлов в каталоге с символическими ссылками, но не для файлов с символическими ссылками вообще
Герхард Бургер
1
Это также полезно unset -v CDPATHдо появления cd, поскольку cd может вызвать нежелательный вывод, если установлен CDPATH.
Binary
Чтобы справиться хотя бы с одним слоем символической ссылки на файл, вы также можете совместимым образом протестировать его с помощью readlink (у macs not -f): scriptDir=$(unset -v CDPATH; cd "$(dirname "$(readlink "$BASH_SOURCE" || echo "$BASH_SOURCE)")" && pwd -P)
Binary
0

Это обрабатывает комбинации символических ссылок и работает с файлами и папками:

#!/usr/bin/env bash
realpath()
{
    if ! pushd $1 &> /dev/null; then 
        pushd ${1##*/} &> /dev/null
        echo $( pwd -P )/${1%/*}
    else
        pwd -P
    fi
    popd > /dev/null
}

Но он не поддерживает realpath -relative-to. Это потребует преобразования, описанного здесь .

Оливер
источник
0

Другой подход:

# Install.
brew install coreutils

# Use the GNU variant.
grealpath --help
FMC
источник