Chuyển đổi đường dẫn tương đối thành đường dẫn tuyệt đối mà không cần liên kết tượng trưng


63

Có một lệnh Unix để có được đường dẫn tuyệt đối (và được chuẩn hóa) từ một đường dẫn tương đối có thể chứa các liên kết tượng trưng không?

Câu trả lời:


79

Bạn có thể sử dụng readlinktiện ích, với -ftùy chọn:

-f, --canonicalize

      canonicalize  by  following  every symlink in every component of
      the given name recursively; all  but  the  last  component  must
      exist

Một số bản phân phối, ví dụ như các bản phân phối sử dụng GNU coreutilsFreeBSD , cũng đi kèm với một realpath(1)tiện ích về cơ bản chỉ gọi realpath(3)và thực hiện khá nhiều điều tương tự.


16
Công -ftắc không tồn tại trên Mac OS X (ít nhất là vào ngày 10.8.5). Không có công -ftắc, nó chỉ trả về mã lỗi.
iconoclast

3
Một số hệ thống đi kèm với không readlinkhay realpath- Solaris và HP-UX, nói riêng.
Sildoreth

Đối với sự cố Mac: brew install coreutils apple.stackexchange.com/a/69332/23040 và nếu bạn không muốn thực hiện bước chuyển hướng tất cả các công cụ Mac CLI tiêu chuẩn sang tương đương GNU mới được cài đặt, chỉ cần gọi greadlink.
Adrian

18

Có thể, PWDbiến được đặt bởi shell thành một vị trí tuyệt đối của thư mục hiện tại. Bất kỳ thành phần nào của đường dẫn đó có thể là một liên kết tượng trưng.

case $f in
  /*) absolute=$f;;
  *) absolute=$PWD/$f;;
esac

Nếu bạn muốn loại bỏ ...cũng vậy, thay đổi thư mục chứa tệp và lấy $PWDở đó:

if [ -d "$f" ]; then f=$f/.; fi
absolute=$(cd "$(dirname -- "$f")"; printf %s. "$PWD")
absolute=${absolute%?}
absolute=$absolute/${f##*/}

Không có cách di động để theo các liên kết tượng trưng. Nếu bạn có một đường dẫn đến một thư mục, thì trên hầu hết các thông báo $(cd -- "$dir" && pwd -P 2>/dev/null || pwd)sẽ cung cấp một đường dẫn không sử dụng các liên kết tượng trưng, ​​bởi vì các trình tự theo dõi các liên kết tượng trưng có xu hướng thực hiện pwd -P(Bối cảnh cho các vật lý của Rằng ).

Một số thông báo cung cấp một tiện ích để in đường dẫn vật lý của thành một tập tin.

  • Các hệ thống Linux gần đây hợp lý (với GNU coreutils hoặc BusyBox) cũng readlink -fnhư FreeBSD ≥8.3, NetBSD ≥4.0 và OpenBSD cho đến tận 2.2.
  • FreeBSD ≥4.3 có realpath(nó cũng có mặt trên một số hệ thống Linux và có trong BusyBox).
  • Nếu Perl có sẵn, bạn có thể sử dụng Cwdmô-đun .

    perl -MCwd -e 'print Cwd::realpath($ARGV[0])' path/to/file

Tại sao bạn đặt một cái gì đó vào pwd( $(cd -- "$dir" && pwd -P 2>/dev/null | pwd))? Nó dường như không quan tâm đến stdin.
Mateusz Piotrowski

1
@MateuszPiotrowski Typo, ý tôi là viết||
Gilles 'SO- ngừng trở thành ác quỷ'

5

pwdphù hợp với nhu cầu của bạn? Nó cho đường dẫn tuyệt đối của thư mục hiện tại. Hoặc có thể những gì bạn muốn là realpath () .


3

alisterrss67trong bài viết này giới thiệu cách ổn định nhất, tương thích và dễ dàng nhất. Tôi chưa bao giờ thấy cách tốt hơn thế này trước đây.

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

Nếu bạn muốn quay lại vị trí ban đầu,

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

hoặc là

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

Tôi muốn điều này giúp. Đây là giải pháp tốt nhất cho tôi.


12
Đó thực sự không phải là một cách tốt. Thay đổi thư mục và quay lại không đáng tin cậy: bạn có thể không được phép quay lại hoặc thư mục có thể đã được đổi tên trong thời gian đó. Thay vào đó, thay đổi thư mục trong một subshell : ABSPATH=$(cd -- "$RELPATH" && pwd). Lưu ý các dấu ngoặc kép xung quanh sự thay thế (để không bị phá vỡ nếu đường dẫn chứa các khoảng trắng và ký tự nối tiếp) và --(trong trường hợp đường dẫn bắt đầu bằng -). Ngoài ra, điều này chỉ hoạt động cho các thư mục, và không hợp thức hóa các liên kết tượng trưng theo yêu cầu. Xem câu trả lời của tôi để biết thêm chi tiết.
Gilles 'SO- ngừng trở nên xấu xa'

"> bạn có thể không được phép quay lại" Ý bạn là cd vào thư mục nhưng không thể cd quay lại? Bạn có thể vui lòng cung cấp một số tình huống ví dụ.
Talespin_Kit

0

Các câu trả lời khác ở đây là tốt nhưng không đủ cho nhu cầu của tôi. Tôi cần một giải pháp mà tôi có thể sử dụng trong các tập lệnh của mình trên bất kỳ máy nào. Giải pháp của tôi là viết một kịch bản shell mà tôi có thể gọi từ các kịch bản mà tôi cần.

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

Giải pháp này được viết cho Bourne Shell cho tính di động. Tôi có cái này trong một kịch bản có tên là "respath.sh".

Kịch bản này có thể được sử dụng như thế này:

respath.sh '/path/to/file'

Hay như thế này

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

Kịch bản giải quyết đường dẫn trong đối số thứ nhất bằng cách sử dụng đường dẫn từ đối số thứ hai làm điểm bắt đầu. Nếu chỉ cung cấp đối số đầu tiên, thì tập lệnh sẽ giải quyết đường dẫn liên quan đến thư mục làm việc hiện tại của bạn.


Lưu ý rằng có lẽ bạn sẽ chỉ tìm thấy vỏ Bourne trên Solaris 10 và trước đó. Vỏ Bourne đó giống như hầu hết các triển khai vỏ Bourne kể từ khi SVR2 (1984) được tích hợp pwdvà không hỗ trợ -P(vỏ Bourne không triển khai xử lý $ PWD hợp lý như các vỏ POSIX).
Stéphane Chazelas

Nếu bạn bỏ khả năng tương thích Bourne, thì bạn có thể sử dụng cú pháp POSIX $ {var ## mẫu} và tránh các echo | sed sắp phá vỡ với một số giá trị.
Stéphane Chazelas

Bạn quên kiểm tra trạng thái thoát của cd (và pwd). Có lẽ bạn cũng nên sử dụng cd -P --trong trường hợp đối số thứ nhất chứa một số ..
Stéphane Chazelas

caseKiểm tra của bạn nên được ..|../*)thay vì ..*.
Stéphane Chazelas

Có một trường hợp thiếu dấu ngoặc kép trongdirname $cwd
Stéphane Chazelas

0

Ngoài ra, trong trường hợp, bạn có một số đường dẫn được xác định trước cho $1(thông thường ${PWD}), sau đây sẽ hoạt động:

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

0

Tôn trọng câu trả lời của mọi người khác, tôi thấy chức năng bên dưới rất dễ dàng và di động giữa linux / MAC OSX so với các ứng dụng khác tôi tìm thấy ở mọi nơi. Có thể giúp ai đó.

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

Giả sử biến a lưu tên đường dẫn (a = "sao cũng được)

1. Đối với đường dẫn chứa không gian tiềm năng:

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

2. Đối với câu hỏi thực tế, tức là chuyển đổi đường dẫn thành tuyệt đối: readlink có thể truy xuất nội dung symlink, có thể được sử dụng như sau. (lưu ý readlink -fsẽ là hoàn hảo nhưng không có sẵn trong bash Mac OS X, trong đó -f là viết tắt của FORMATS .)

if [[ $(readlink $a) == "" ]]; then a=$(cd $a; pwd); else a=$(cd $(readlink $a); pwd); fi

3. Chỉ học pwd -Ptrong man pwd: -P là " Hiển thị thư mục làm việc hiện tại vật lý (tất cả các liên kết tượng trưng đã được giải quyết) " và do đó

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

cũng sẽ làm việc

Kết luận: kết hợp 1 với 2 để đáp ứng cả hai yêu cầu của bạn, trong khi các tên đường dẫn chứa không gian đã được xử lý trong 3 ngắn gọn hơn .


Bạn gu (r) luận sai. Ví dụ: nếu đường dẫn của bạn bao gồm một không gian hầu hết không hoạt động.
Anthon

hoặc một char toàn cầu đôi khi. Và nó không giải quyết các liên kết tượng trưng, ​​như được yêu cầu.
dave_thndry_085

Tôi đã xóa phản hồi "bình luận" của mình về tên đường dẫn chứa khoảng trắng và sửa đổi phần "trả lời" tương ứng.
vxtal
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.