Преобразование относительного пути к полному пути без символьной ссылки

Я регулярно не использую его, но neercs утверждает, что поддерживал это. Это - a screen- как программа с разными необычными функциями как лучшее управление областью, но главное это предлагает, способность импортировать процесс в область

65
12.10.2018, 15:16
8 ответов

Можно использовать 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, также идут с a realpath(1) утилита, которая в основном просто звонит realpath(3) и делает в значительной степени то же самое.

81
27.01.2020, 19:32
  • 1
    -f переключатель не существует на Mac OS X (по крайней мере, с 10.8.5). Без -f переключитесь это просто возвращает код ошибки. –  iconoclast 27.09.2013, 05:43
  • 2
    Некоторые системы не идут ни с одним readlink ни realpath – Солярис и HP-UX, в частности. –  Sildoreth 22.05.2015, 18:09

Портативно, 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” для “физического”).

Некоторые нельды обеспечивают утилиту для печати “физического” пути к файлу.

  • Довольно недавние системы Linux (с GNU coreutils или BusyBox) имеют readlink -f также как и FreeBSD ≥8.3, NetBSD ≥4.0 и OpenBSD еще 2.2.
  • FreeBSD ≥4.3 имеет realpath (это также присутствует в некоторых системах Linux, и это находится в BusyBox).
  • Если Perl доступен, можно использовать Cwd модуль.

    perl -MCwd -e 'print Cwd::realpath($ARGV[0])' path/to/file
    
21
27.01.2020, 19:32
  • 1
    Почему Вы передаете что-то по каналу в pwd ($(cd -- "$dir" && pwd -P 2>/dev/null | pwd))? Это, кажется, не заботится о stdin. –  Mateusz Piotrowski 17.03.2017, 01:39
  • 2
    @MateuszPiotrowski, я означал писать || –  Gilles 'SO- stop being evil' 17.03.2017, 02:05

pwd подходящий для Ваших потребностей? Это дает полный путь текущего каталога. Или возможно то, что Вы хотите, является realpath ().

5
27.01.2020, 19:32

alister и rss67 в этой статье представляют самый стабильный, совместимый и самый легкий путь. Я никогда замечаемый лучший путь, чем это прежде.

RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`

Если Вы хотите вернуться к исходному местоположению,

ORGPATH=`pwd`
RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`
cd $ORGPATH

или

RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`
cd -

Я желаю, чтобы это помогло. Это было самым большим решением для меня.

3
27.01.2020, 19:32
  • 1
    Это - на самом деле не такой хороший путь. Изменение из каталога и въезжает задним ходом, не надежно: у Вас не могло бы быть разрешения возвратиться, или каталог, возможно, был переименован тем временем. Вместо этого каталоги изменения в подоболочке: ABSPATH=$(cd -- "$RELPATH" && pwd). Отметьте двойные кавычки вокруг замены (чтобы не повредиться, если путь содержит пробел и globbing символы), и -- (в случае, если путь начинается -). Также это только работает на каталоги и не канонизирует символьные ссылки согласно просьбе. Дополнительную информацию см. в моем ответе. –  Gilles 'SO- stop being evil' 27.09.2012, 11:49

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

#!/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'

Скрипт разрешает путь в первом аргументе, используя путь от второго аргумента в качестве отправной точки. Если предоставлен только первый аргумент, то сценарий разрешает путь относительно вашей текущей рабочей директории.

0
27.01.2020, 19:32

Предположим, что переменная a хранит имя пути (a = "что угодно")

1. Для потенциального пути, содержащего пробелы:

 c = $ (grep -o "" <<< $ a | wc -l); если (($ c> "0")); тогда a = $ (sed 's / / \\ / g' <<< $ a); fi 
 

2. Что касается фактического вопроса, то есть преобразования пути в абсолютный: readlink может получить содержимое символической ссылки, которое можно использовать следующим образом. (примечание readlink -f было бы идеально, но он недоступен по крайней мере в Mac OS X bash, в котором -f означает FORMATS .)

 если [[$ (readlink $ a) == ""]]; тогда a = $ (cd $ a; pwd); иначе a = $ (cd $ (readlink $ a); pwd); fi 
 

3. Только что изучил pwd -P в man pwd : -P означает « Показать физический текущий рабочий каталог (все символьные ссылки разрешены) » и, следовательно,

 if (($ (grep -o "" <<< $ a | wc -l)> "0")); тогда a = $ (sed 's / / \\ / g' <<< $ a); fi; a = $ (cd $ a; pwd -P) 
 

тоже подойдет.

Заключение: объедините 1 с 2 , чтобы удовлетворить оба ваших требования, в то время как имена путей, содержащие пробелы, уже учтены в более кратком 3 .

-1
27.01.2020, 19:32

Если, кроме того, у вас есть предопределенный путь для $1(, обычно ${PWD}), будет работать следующее:

CWD="${1:-${PredefinedAbsolutePath}}"
if [ "${CWD}" != "${PredefinedAbsolutePath}}" ]; then
    case $1 in
        /*) echo "CWD=${CWD}"; ;;
        *) CWD=$(realpath $1); echo "CWD=${CWD}"; ;;
    esac
fi
0
27.01.2020, 19:32

Уважая все остальные ответы, я обнаружил, что функция ниже очень проста и переносима между 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
0
27.01.2020, 19:32

Теги

Похожие вопросы