Подтвердить что ты не робот

Как получить абсолютное имя пути оболочки script на MacOS?

readlink -f не существует на MacOS. Единственное работающее решение для Mac OS, которое мне удалось найти в сети, выглядит следующим образом:

if [[ $(echo $0 | awk '/^\//') == $0 ]]; then
    ABSPATH=$(dirname $0)
else
    ABSPATH=$PWD/$(dirname $0)
fi

Может ли кто-нибудь предложить что-нибудь более элегантное для этой кажущейся тривиальной задачи?

4b9b3361

Ответ 1

Другой (также довольно уродливый) вариант:

ABSPATH=$(cd "$(dirname "$0")"; pwd)

Ответ 2

Получить абсолютный путь оболочки script

Выкопали некоторые старые сценарии из моего .bashrc и немного обновили синтаксис, добавили тестовый набор.

Поддержка

  • source./ script (Когда вызывается оператором . dot)
  • Абсолютный путь/путь/в/script
  • Относительный путь, как. /script
  • /path/dir1/../dir2/dir3/../script
  • При вызове из символической ссылки
  • Когда символическая ссылка вложена, например) foo->dir1/dir2/bar bar->./../doe doe->script
  • Когда вызывающий абонент меняет имя скрипта

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

код

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

Известный issuse

Script должен быть на диске где-то, пусть он будет по сети. Если вы попытаетесь запустить этот script из PIPE, он не будет работать

wget -o /dev/null -O - http://host.domain/dir/script.sh |bash

С технической точки зрения, это undefined.
Практически говоря, нет разумного способа обнаружить это.

Используемый тестовый пример

И текущий тестовый пример, который проверяет, что он работает.

#!/bin/bash
# setup test enviroment
mkdir -p dir1/dir2
mkdir -p dir3/dir4
ln -s ./dir1/dir2/foo bar
ln -s ./../../dir3/dir4/test.sh dir1/dir2/foo
ln -s ./dir1/dir2/foo2 bar2
ln -s ./../../dir3/dir4/doe dir1/dir2/foo2
cp test.sh ./dir1/dir2/
cp test.sh ./dir3/dir4/
cp test.sh ./dir3/dir4/doe
P="`pwd`"
echo "--- 01"
echo "base  =[${P}]" && ./test.sh
echo "--- 02"
echo "base  =[${P}]" && `pwd`/test.sh
echo "--- 03"
echo "base  =[${P}]" && ./dir1/dir2/../../test.sh
echo "--- 04"
echo "base  =[${P}/dir3/dir4]" && ./bar
echo "--- 05"
echo "base  =[${P}/dir3/dir4]" && ./bar2
echo "--- 06"
echo "base  =[${P}/dir3/dir4]" && `pwd`/bar
echo "--- 07"
echo "base  =[${P}/dir3/dir4]" && `pwd`/bar2
echo "--- 08"
echo "base  =[${P}/dir1/dir2]" && `pwd`/dir3/dir4/../../dir1/dir2/test.sh
echo "--- 09"
echo "base  =[${P}/dir1/dir2]" && ./dir1/dir2/test.sh
echo "--- 10"
echo "base  =[${P}/dir3/dir4]" && ./dir3/dir4/doe
echo "--- 11"
echo "base  =[${P}/dir3/dir4]" && ./dir3/dir4/test.sh
echo "--- 12"
echo "base  =[${P}/dir3/dir4]" && `pwd`/dir3/dir4/doe
echo "--- 13"
echo "base  =[${P}/dir3/dir4]" && `pwd`/dir3/dir4/test.sh
echo "--- 14"
echo "base  =[${P}/dir3/dir4]" && `pwd`/dir1/dir2/../../dir3/dir4/doe
echo "--- 15"
echo "base  =[${P}/dir3/dir4]" && `pwd`/dir1/dir2/../../dir3/dir4/test.sh
echo "--- 16"
echo "base s=[${P}]" && source test.sh
echo "--- 17"
echo "base s=[${P}]" && source `pwd`/test.sh
echo "--- 18"
echo "base s=[${P}/dir1/dir2]" && source ./dir1/dir2/test.sh
echo "--- 19"
echo "base s=[${P}/dir3/dir4]" && source ./dir1/dir2/../../dir3/dir4/test.sh
echo "--- 20"
echo "base s=[${P}/dir3/dir4]" && source `pwd`/dir1/dir2/../../dir3/dir4/test.sh
echo "--- 21"
pushd . >/dev/null
cd ..
echo "base x=[${P}/dir3/dir4]"
./`basename "${P}"`/bar
popd  >/dev/null

PurpleFox aka GreenFox

Ответ 3

Используя bash, я предлагаю этот подход. Вы сначала cd в каталог, затем вы берете текущий каталог с помощью pwd. После этого вы должны вернуться в старый каталог, чтобы ваш script не создавал побочные эффекты для другого вызывающего его script.

cd "$(dirname -- "$0")"
dir="$PWD"
echo "$dir"
cd - > /dev/null

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

Примечание: требуется /dev/null или "cd -" напечатать путь, к которому он возвращается.

Ответ 4

Также обратите внимание, что homebrew (http://brew.sh) coreutils пакет включает realpath (ссылка создана в /opt/local/bin).

$ realpath bin
/Users/nhed/bin

Ответ 5

Если вы не против использования perl:

ABSPATH=$(perl -MCwd=realpath -e "print realpath '$0'")

Ответ 6

Можете ли вы попробовать что-то подобное в своем script?

echo $(pwd)/"$0"

В моей машине он показывает:

/home/barun/codes/ns2/link_down/./test.sh

который является абсолютным именем пути оболочки script.

Ответ 7

Я нашел, что это полезно для символических ссылок/динамических ссылок - работает с GNU readlink только (из-за флага -f):

# detect if GNU readlink is available on OS X
if [ "$(uname)" = "Darwin" ]; then
  which greadlink > /dev/null || {
    printf 'GNU readlink not found\n'
    exit 1
  }
  alias readlink="greadlink"
fi

# create a $dirname variable that contains the file dir
dirname=$(dirname "$(readlink -f "$0")")

# use $dirname to find a relative file
cat "$dirname"/foo/bar.txt

Ответ 8

это то, что я использую, может потребоваться настройка здесь или там

abspath () 
{ 
    case "${1}" in 
        [./]*)
            local ABSPATH="$(cd ${1%/*}; pwd)/${1##*/}"
            echo "${ABSPATH/\/\///}"
        ;;
        *)
            echo "${PWD}/${1}"
        ;;
    esac
}

Это для любого файла - и проклятия вы можете просто вызвать его как abspath ${0}

Первый случай касается относительных путей с помощью cd-ing для пути и предоставления возможности pwd

Второй случай предназначен для работы с локальным файлом (где ${1 ##/} не работал)

Это НЕ пытается отменить символические ссылки!

Ответ 9

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

ABSPATH=$(dirname $(pwd -P $0)/${0#\.\/})

Ответ 10

Если вы используете ksh, параметр ${.sh.file} устанавливается в абсолютный путь к script. Чтобы получить родительский каталог script: ${.sh.file%/*}

Ответ 11

Я использую функцию ниже, чтобы эмулировать readlink -f для сценариев, которые должны работать как в Linux, так и в Mac OS X.

#!/bin/bash
# This was re-worked on 2018-10-26 after [email protected] correctly
# observed that the previous version did not work.

# Works on both linux and Mac OS X.
# The "pwd -P" re-interprets all symlinks.
function read-link() {
    local path=$1
    if [ -d $path ] ; then
        local abspath=$(cd $path; pwd -P)
    else
        local prefix=$(cd $(dirname -- $path) ; pwd -P)
        local suffix=$(basename $path)
        local abspath="$prefix/$suffix"
    fi
    if [ -e $abspath ] ; then
        echo $abspath
    else
        echo 'error: does not exist'
    fi
}

# Example usage.
while (( $# )) ; do
    printf '%-24s - ' "$1"
    read-link $1
    shift
done

Это вывод для некоторых распространенных целей Mac OS X:

$ ./example.sh /usr/bin/which /bin/which /etc/racoon ~/Downloads
/usr/bin/which           - /usr/bin/which
/bin/which               - error: does not exist
/etc/racoon              - /private/etc/racoon
/Users/jlinoff/Downloads - /Users/jlinoff/Downloads

Это вывод для некоторых целей Linux.

$ ./example.sh /usr/bin/which /bin/whichx /etc/init.d ~/Downloads
/usr/bin/which           - /usr/bin/which
/bin/whichx              - error: does not exist
/etc/init.d              - /etc/init.d
/home/jlinoff/Downloads  - /home/jlinoff/Downloads