Получить исходный каталог скрипта Bash из самого скрипта - PullRequest
4414 голосов
/ 13 сентября 2008

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

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

$ ./application

Ответы [ 58 ]

0 голосов
/ 24 января 2009

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

LIBDIR=$(dirname "$(readlink -f "$(type -P $0 || echo $0)")")
source $LIBDIR/lib.sh
0 голосов
/ 28 июня 2009
ME=`type -p $0`
MDIR="${ME%/*}"
WORK_DIR=$(cd $MDIR && pwd)
0 голосов
/ 03 октября 2013

Очень поздно к обсуждению, но попробуйте что-то вроде этого:

function get_realpath() {

if [[ -f "$1" ]]
then
    # file *must* exist
    if cd "$(echo "${1%/*}")" &>/dev/null
    then
        # file *may* not be local
        # exception is ./file.ext
        # try 'cd .; cd -;' *works!*
        local tmppwd="$PWD"
        cd - &>/dev/null
    else
        # file *must* be local
        local tmppwd="$PWD"
    fi
else
    # file *cannot* exist
    return 1 # failure
fi

# reassemble realpath
echo "$tmppwd"/"${1##*/}"
return 0 # success

}

function get_dirname(){

local realpath="$(get_realpath "$1")"
if (( $? )) # true when non-zero.
then
    return $? # failure
fi
echo "${realpath%/*}"
return 0 # success

}

# Then from the top level:
get_dirname './script.sh'

# Or Within a script:
get_dirname "$0"

# Can even test the outcome!
if (( $? )) # true when non-zero.
then
    exit 1 # failure
fi

Эти функции и связанные с ними инструменты являются частью нашего продукта, который был предоставлен сообществу бесплатно, и его можно найти на GitHub как realpath-lib . Он простой, чистый и хорошо документированный (отлично подходит для обучения), чистый Bash и не имеет никаких зависимостей. Хорошо для кроссплатформенного использования тоже. Таким образом, для приведенного выше примера внутри скрипта вы можете просто:

source '/path/to/realpath-lib'

get_dirname "$0"

if (( $? )) # true when non-zero.
then
    exit 1 # failure
fi

Вот и все!

0 голосов
/ 29 ноября 2009
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
0 голосов
/ 26 марта 2019

Ниже хранит путь к каталогу скрипта в dir переменная

(также он пытается поддерживать выполнение в Cygwin с использованием Windows php)

и, наконец, он запускает исполняемый файл my-sample-app со всеми аргументами, переданными этому сценарию с использованием "$@"

#!/usr/bin/env sh

dir=$(cd "${0%[/\\]*}" > /dev/null && pwd)

if [ -d /proc/cygdrive ]; then
    case $(which php) in
        $(readlink -n /proc/cygdrive)/*)
            # We are in Cygwin using Windows php, so the path must be translated
            dir=$(cygpath -m "$dir");
            ;;
    esac
fi

# Runs the executable which is beside this script
"${dir}/my-sample-app" "$@"
0 голосов
/ 10 января 2019

выбранный ответ работает очень хорошо. Я публикую свое решение для тех, кто ищет более короткие альтернативы, которые все еще касаются поиска, выполнения, полных путей, относительных путей и символических ссылок. Наконец, это будет работать на MacOS, учитывая, что нельзя предполагать, что доступна версия readlink для GNU coreutils.

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

PHP доступен на MacOS по умолчанию и установлен на ряде других платформ, хотя не обязательно по умолчанию. Я понимаю, что это недостаток, но я все равно оставлю это здесь для всех, кто приходит из поисковых систем.

export SOURCE_DIRECTORY="$(php -r 'echo dirname(realpath($argv[1]));' -- "${BASH_SOURCE[0]}")"
0 голосов
/ 24 мая 2014
cur_dir=`old=\`pwd\`; cd \`dirname $0\`; echo \`pwd\`; cd $old;`
0 голосов
/ 27 ноября 2013

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

... Ну, как видите, с некоторой помощью я нашел довольно простое и очень мощное решение:

Я могу передать функции своего рода переменную мессенджера и разыменовать любое явное использование имени $1 аргумента результирующей функции с eval при необходимости, и, по завершении подпрограммы функции, я использую eval и трюк с обратными слэшами, чтобы присвоить моей переменной-посланнику желаемое значение, даже не зная ее имени.

В полном раскрытии, ... [я нашел переменную часть посланника этого] и в трюки Рича , и я также извлек соответствующую часть его страницы ниже выдержки из моего собственного ответа.

... ВЫПИСКА: ...

Хотя это и не строго POSIX, realpath является базовым приложением GNU с 2012 года . Полное раскрытие: никогда не слышал об этом до того, как я заметил это в info coreutils TOC и сразу подумал о [связанном] вопросе, но использование следующей функции, как продемонстрировано, должно надежно, (скоро МОЖНО?), И, я надеюсь, эффективно предоставить вызывающему абоненту абсолютно источник $0:

% _abs_0() { 
> o1="${1%%/*}"; ${o1:="${1}"}; ${o1:=`realpath -s "${1}"`}; eval "$1=\${o1}"; 
> }  
% _abs_0 ${abs0:="${0}"} ; printf %s\\n "${abs0}"
/no/more/dots/in/your/path2.sh

РЕДАКТИРОВАТЬ: Возможно, стоит подчеркнуть, что это решение использует расширение параметра POSIX , чтобы сначала проверить, нужно ли вообще расширять и разрешать путь, прежде чем пытаться сделать это. Это должно вернуть абсолютно источник $0 через переменную мессенджера (с заметным исключением, что он сохранит symlinks) как эффективно , как я мог себе представить это может быть сделано независимо от того, является ли путь уже абсолютным. ...

( незначительное редактирование : перед тем, как найти в документах realpath, я по крайней мере урезал свою версию [нижеприведенной версии], чтобы она не зависела от поля времени [как это происходит в первой команде ps, но, честное предупреждение, после тестирования некоторых я менее убежден, ps полностью надежен в своей способности расширения пути команд )

С другой стороны, вы можете сделать это:

ps ww -fp $$ | grep -Eo '/[^:]*'"${0#*/}"

eval "abs0=${`ps ww -fp $$ | grep -Eo ' /'`#?}"

... А из трюки Рича : ...

Возвращение строк из функции оболочки

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

Попробуйте это:

func () {
body here
eval "$1=\${foo}"
}

Конечно, ${foo} можно заменить любым видом замены. Ключевой трюк здесь - это оценка линии и использование экранирования. “$1” раскрывается, когда аргумент для eval создается основным анализатором команд. Но “${foo}” на этом этапе не раскрывается, потому что “$” указан в кавычках. Вместо этого он расширяется, когда eval оценивает свой аргумент. Если неясно, почему это важно, подумайте о том, как будет плохо:

foo='hello ; rm -rf /'
dest=bar
eval "$dest=$foo"

Но, конечно, следующая версия совершенно безопасна:

foo='hello ; rm -rf /'
dest=bar
eval "$dest=\$foo"

Обратите внимание, что в исходном примере “$1” использовался, чтобы позволить вызывающей стороне передать имя переменной назначения в качестве аргумента функции. Если вашей функции необходимо использовать команду shift, например, для обработки оставшихся аргументов как “$@”, то может быть полезно сохранить значение “$1” во временной переменной в начале функции.

0 голосов
/ 17 апреля 2018

Вот как я работаю над сценариями: pathvar="$( cd "$( dirname $0 )" && pwd )" Это скажет вам, из какого каталога запускается Launcher (текущий скрипт).

0 голосов
/ 14 ноября 2014
FOLDERNAME=${PWD##*/}

это самый быстрый способ, которым я знаю

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...