Ответы:
Вы можете использовать readlink
утилиту с -f
опцией:
-f, --canonicalize
canonicalize by following every symlink in every component of the given name recursively; all but the last component must exist
Некоторые дистрибутивы, например те, которые используют GNU coreutils и FreeBSD , также поставляются с realpath(1)
утилитой, которая в основном просто вызывает realpath(3)
и делает почти то же самое.
readlink
ни realpath
Solaris, ни HP-UX, в частности.
brew install coreutils
apple.stackexchange.com/a/69332/23040 , и если вы не хотите делать шаг, который перенаправляет все стандартные инструменты CLI Mac к недавно установленным эквивалентам GNU, просто позвоните greadlink
.
Портативно, PWD
переменная устанавливается оболочкой в одно абсолютное местоположение текущего каталога. Любой компонент этого пути может быть символической ссылкой.
case $f in
/*) absolute=$f;;
*) absolute=$PWD/$f;;
esac
Если вы хотите устранить .
и ..
как хорошо, перейдите в каталог , содержащий файл и получить $PWD
там:
if [ -d "$f" ]; then f=$f/.; fi
absolute=$(cd "$(dirname -- "$f")"; printf %s. "$PWD")
absolute=${absolute%?}
absolute=$absolute/${f##*/}
Нет переносимого способа перейти по символическим ссылкам. Если у вас есть путь к каталогу, то в большинстве устройств $(cd -- "$dir" && pwd -P 2>/dev/null || pwd)
есть путь, который не использует символические ссылки, потому что оболочки, которые отслеживают символические ссылки, имеют тенденцию реализовываться pwd -P
(«P» для «физического»).
Некоторые устройства предоставляют утилиту для печати «физического» пути к файлу.
readlink -f
, как и FreeBSD ≥8.3, NetBSD ≥4.0 и OpenBSD еще до 2.2.realpath
(он также присутствует в некоторых системах Linux и в BusyBox).Если Perl доступен, вы можете использовать Cwd
модуль .
perl -MCwd -e 'print Cwd::realpath($ARGV[0])' path/to/file
pwd
( $(cd -- "$dir" && pwd -P 2>/dev/null | pwd)
)? Кажется, это не заботится о stdin.
||
Является ли pwd
подходит для ваших нужд? Это дает абсолютный путь к текущему каталогу. Или, может быть, вам нужен realpath () .
alister
и rss67
в этой статье представим наиболее стабильный, совместимый и простой способ. Я никогда не видел лучшего способа, чем этот.
RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`
Если вы хотите вернуться в исходное местоположение,
ORGPATH=`pwd`
RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`
cd $ORGPATH
или же
RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`
cd -
Я хотел бы, чтобы это помогло. Это было лучшее решение для меня.
ABSPATH=$(cd -- "$RELPATH" && pwd)
. Обратите внимание на двойные кавычки вокруг подстановки (чтобы не разрывать, если путь содержит пробелы и символы с пробелами) и --
(в случае, если путь начинается с -
). Также это работает только для каталогов и не канонизирует символические ссылки в соответствии с запросом. Смотрите мой ответ для более подробной информации.
Другие ответы здесь были хороши, но были недостаточны для моих нужд. Мне нужно было решение, которое я мог бы использовать в своих скриптах на любом компьютере. Моим решением было написать сценарий оболочки, который я могу вызывать из сценариев, где он мне нужен.
#!/bin/sh
if [ $# -eq 0 ] || [ $# -gt 2 ]; then
printf 'Usage: respath path [working-directory]\n' >&2
exit 1
fi
cantGoUp=
path=$1
if [ $# -gt 1 ]; then
cd "$2"
fi
cwd=`pwd -P` #Use -P option to account for directories that are actually symlinks
#Handle non-relative paths, which don't need resolution
if echo "$path" | grep '^/' > /dev/null ; then
printf '%s\n' "$path"
exit 0
fi
#Resolve for each occurrence of ".." at the beginning of the given path.
#For performance, don't worry about ".." in the middle of the path.
while true
do
case "$path" in
..*)
if [ "$cwd" = '/' ]; then
printf 'Invalid relative path\n' >&2
exit 1
fi
if [ "$path" = '..' ]; then
path=
else
path=`echo "$path" | sed 's;^\.\./;;'`
fi
cwd=`dirname $cwd`
;;
*)
break
;;
esac
done
cwd=`echo "$cwd" | sed 's;/$;;'`
if [ -z "$path" ]; then
if [ -z "$cwd" ]; then
cwd='/'
fi
printf '%s\n' "$cwd"
else
printf '%s/%s\n' "$cwd" "$path"
fi
Это решение написано для Bourne Shell для переносимости. У меня есть это в сценарии с именем "respath.sh".
Этот скрипт можно использовать так:
respath.sh '/path/to/file'
Или вот так
respath.sh '/relative/path/here' '/path/to/resolve/relative/to'
Сценарий разрешает путь в первом аргументе, используя путь из второго аргумента в качестве начальной точки. Если указан только первый аргумент, сценарий разрешает путь относительно вашего текущего рабочего каталога.
pwd
встроенную функцию и не поддерживает ее -P
(оболочка Bourne не реализовала такую логическую обработку $ PWD, как это делают оболочки POSIX).
cd -P --
также в случае, если 1-й аргумент содержит некоторые ..
case
чек должен быть ..|../*)
вместо ..*
.
dirname $cwd
В случае, если, кроме того, у вас есть некоторый предопределенный путь для $1
(обычно ${PWD}
), будет работать следующее:
CWD="${1:-${PredefinedAbsolutePath}}"
if [ "${CWD}" != "${PredefinedAbsolutePath}}" ]; then
case $1 in
/*) echo "CWD=${CWD}"; ;;
*) CWD=$(realpath $1); echo "CWD=${CWD}"; ;;
esac
fi
Уважая ответ всех остальных, я обнаружил, что приведенная ниже функция очень проста и удобна для переноса между linux / MAC OSX, чем другие, которые я нашел везде. Может помочь кому-нибудь.
#!/usr/bin/bash
get_absolute_path(){
file_path=`pwd $1`
echo "$file_path/$1"
}
#to assign to a variable
absolute_path=$(get_absolute_path "file.txt")
echo $absolute_path
Предположим, что переменная a хранит имя пути (a = "what")
1. Для потенциального пространства, содержащего путь:
c=$(grep -o " " <<< $a | wc -l); if (( $c > "0" )); then a=$(sed 's/ /\\ /g' <<< $a); fi
2. Для актуального вопроса, т.е. преобразования пути в абсолютный: readlink может получить содержимое символической ссылки, которое можно использовать следующим образом. (примечание readlink -f
было бы идеально, но не доступно по крайней мере в Mac OS X bash, в котором -f обозначает ФОРМАТЫ .)
if [[ $(readlink $a) == "" ]]; then a=$(cd $a; pwd); else a=$(cd $(readlink $a); pwd); fi
3. Только что узнал pwd -P
в man pwd
: -P это « Показать физический текущий рабочий каталог (все символические ссылки разрешены) » и, следовательно,
if (( $(grep -o " " <<< $a | wc -l) > "0" )); then a=$(sed 's/ /\\ /g' <<< $a); fi; a=$(cd $a; pwd -P)
работать тоже буду.
Вывод: объедините 1 с 2, чтобы удовлетворить оба ваших требования, в то время как имена путей, содержащие пробелы, уже рассмотрены в более кратком 3 .
-f
Переключатель не существует на Mac OS X (по крайней мере , по состоянию на 10.8.5). Без-f
переключателя он просто возвращает код ошибки.