Перетворення відносного шляху в абсолютний шлях без символічного зв’язку


63

Чи є команда Unix для отримання абсолютного (і канонізованого) шляху з відносного шляху, який може містити символічні посилання?

Відповіді:


79

Ви можете скористатися 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)і робить майже те саме.


16
-fПеремикач не існує на Mac OS X (принаймні , за станом на 10.8.5). Без -fкомутатора він просто повертає код помилки.
іконоборство

3
Деякі системи не входять ні з жодним, readlinkні з realpathSolaris та HP-UX, зокрема.
Сілдорет

Що стосується проблеми з Mac: brew install coreutils apple.stackexchange.com/a/69332/23040 , і якщо ви не хочете робити кроку, який перенаправляє всі стандартні інструменти Mac CLI до нещодавно встановлених еквівалентів GNU, просто зателефонуйте greadlink.
Адріан

18

Портативно, 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

Чому ти вкладаєш щось у pwd( $(cd -- "$dir" && pwd -P 2>/dev/null | pwd))? Це, здається, не хвилює stdin.
Матеуш Піотровський

1
@MateuszPiotrowski помилка, я хотів написати||
Жиль

5

Чи pwdвідповідає вашим потребам? Це дає абсолютний шлях поточного каталогу. А може, те, що ви хочете, це realpath () .


3

alisterі rss67в цій статті представити найбільш стабільний, сумісний і найпростіший спосіб. Я ніколи не бачив кращого способу, ніж це раніше.

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

Якщо ви хочете повернутися до початкового місця,

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

або

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

Я хочу, щоб це допомагало. Це було найбільшим рішенням для мене.


12
Це насправді не такий вдалий спосіб. Зміна каталогу та повернення до нього не є надійним: у вас може не бути дозволу на повернення, або каталог тим часом може бути перейменований. Замість цього, змінити каталоги в субоболочке: ABSPATH=$(cd -- "$RELPATH" && pwd). Зверніть увагу на подвійні лапки навколо підстановки (щоб не порушити, якщо шлях містить пробіли та символи глобусу) та --(у випадку, якщо шлях починається з -). Крім того, це працює лише для каталогів, і не канонізує символічні посилання за запитом. Дивіться мою відповідь для отримання більш детальної інформації.
Жиль

"> у вас, можливо, немає дозволу повертатися" Ви маєте на увазі CD на dir, але не можете CD назад? Надайте, будь ласка, кілька прикладних сценаріїв.
Talespin_Kit

0

Інші відповіді тут були чудовими, але були недостатніми для моїх потреб. Мені потрібно було рішення, яке я міг би використовувати в своїх сценаріях на будь-якій машині. Моє рішення полягало в тому, щоб написати скрипт оболонки, який я можу викликати із скриптів, де мені це потрібно.

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

Це рішення написано для оболонки Борна для переносимості. Я маю це у сценарії під назвою "respath.sh".

Цей сценарій можна використовувати так:

respath.sh '/path/to/file'

Або так

respath.sh '/relative/path/here' '/path/to/resolve/relative/to'

Сценарій вирішує шлях у першому аргументі, використовуючи шлях від другого аргументу як вихідну точку. Якщо надається лише перший аргумент, то сценарій вирішує шлях відносно вашої поточної робочої каталоги.


Зверніть увагу, що ви, ймовірно, знайдете оболонку Борна на Solaris 10 та більш ранніх часів. Ця оболонка Bourne, як і більшість реалізацій оболонки Bourne, оскільки SVR2 (1984) pwdвбудована і не підтримує -P(оболонка Bourne не реалізувала таку логічну обробку $ PWD, як це роблять оболонки POSIX).
Стефан Шазелас

Якщо ви скасуєте сумісність Bourne, ви можете використовувати синтаксис POSIX $ {var ## pattern} і уникнути тих ехо | sed, які зірвуться з деякими значеннями.
Стефан Шазелас

Забудьте перевірити стан виходу CD (та pwd). Ви , ймовірно , слід використовувати cd -P --також і в разі першого аргументу містить деякі ..
Stéphane Chazelas

Ваш caseчек має бути ..|../*)замість ..*.
Стефан Шазелас

Є один випадок пропуску цитатdirname $cwd
Стефан Шазелас

0

У разі, якщо у вас є якийсь попередньо визначений шлях для $1(як правило ${PWD}), працює наступне:

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

0

Поважаючи відповідь усіх інших, я знайшов функцію нижче дуже легкою та портативною між 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

-1

Припустимо, змінна a зберігає назву шляху (a = "що завгодно")

1. Для потенційного вмісту, що містить простір:

c=$(grep -o " " <<< $a | wc -l); if (( $c > "0" )); then a=$(sed 's/ /\\ /g' <<< $a); fi

2. Для власне питання, тобто перетворення шляху в абсолютний: readlink може отримати вміст симпосилання , яке можна використовувати наступним чином. (зауважте, readlink -fце було б ідеально, але воно не доступне принаймні в басі Mac OS X, в якому -f означає FORMATS .)

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 .


Ви помиляєтесь. Наприклад, якщо ваш шлях включає пробіл, більшість з вищевказаних робіт.
Антон

або глобус іноді. І це не вирішує символьні посилання, як цього вимагали.
dave_thompson_085

Я видалив свою відповідь "коментар" стосовно імен шляхів, що містять пробіли, і відповідно змінив частину "відповідь".
vxtal
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.