2008-08-11 31 views
175

Với đường dẫn tuyệt đối hoặc tương đối (trong hệ thống giống Unix), tôi muốn xác định đường dẫn đầy đủ của đích sau khi giải quyết bất kỳ liên kết trung gian nào. Điểm thưởng để cũng giải quyết ký hiệu tên người dùng ~ cùng một lúc.Cách xử lý liên kết tượng trưng trong tập lệnh shell

Nếu đích là thư mục, có thể chdir() vào thư mục và sau đó gọi getcwd(), nhưng tôi thực sự muốn làm điều này từ tập lệnh shell thay vì viết trình trợ giúp C. Thật không may, vỏ có xu hướng cố gắng che giấu sự tồn tại của liên kết tượng trưng từ người sử dụng (đây là bash trên OS X):

$ ls -ld foo bar 
drwxr-xr-x 2 greg greg 68 Aug 11 22:36 bar 
lrwxr-xr-x 1 greg greg 3 Aug 11 22:36 foo -> bar 
$ cd foo 
$ pwd 
/Users/greg/tmp/foo 
$ 

Những gì tôi muốn là một chức năng quyết tâm() sao cho khi thực hiện từ thư mục tmp trong ví dụ trên, giải quyết ("foo") == "/ Users/greg/tmp/bar".

Trả lời

79

Theo tiêu chuẩn, pwd -P phải trả lại đường dẫn có liên kết tượng trưng được giải quyết.

Chức năng C char *getcwd(char *buf, size_t size) từ unistd.h phải có cùng hành vi.

getcwd pwd

+13

này chỉ làm việc cho thư mục (hiện tại)? Nếu mục tiêu là một tập tin, nó sẽ không cung cấp bất cứ điều gì ... – dala

+2

Không hoạt động nếu liên kết bị hỏng vì bạn không thể biến nó thành đường dẫn hiện tại của bạn –

+3

Tóm lại với lợi ích của sự nhận thức muộn: Câu trả lời này chỉ hoạt động trong những trường hợp rất hạn chế , cụ thể là nếu liên kết tượng trưng quan tâm đến _directory_ thực sự là _exists_; Ngoài ra, bạn phải 'cd' cho nó trước, trước khi gọi' pwd -P'. Nói cách khác: nó sẽ không cho phép bạn giải quyết (xem mục tiêu) symlink _to files_ hoặc của các liên kết tượng trưng _broken_, và để giải quyết các liên kết thư mục hiện có, bạn phải thực hiện thêm công việc (khôi phục lại thư mục làm việc trước đó hoặc bản địa hoá ' cd' và 'pwd -P' cuộc gọi trong một subshell). – mklement0

1

kịch bản shell chung thường phải tìm "nhà" của họ thư mục ngay cả khi họ được gọi là một liên kết tượng trưng. Do đó, kịch bản phải tìm vị trí "thực" của họ chỉ với $ 0.

cat `mvn` 

trên hệ thống của tôi in một tập lệnh có chứa nội dung sau, đây là gợi ý hay về những gì bạn cần.

if [ -z "$M2_HOME" ] ; then 
    ## resolve links - $0 may be a link to maven's home 
    PRG="$0" 

    # need this for relative symlinks 
    while [ -h "$PRG" ] ; do 
    ls=`ls -ld "$PRG"` 
    link=`expr "$ls" : '.*-> \(.*\)$'` 
    if expr "$link" : '/.*' > /dev/null; then 
     PRG="$link" 
    else 
     PRG="`dirname "$PRG"`/$link" 
    fi 
    done 

    saveddir=`pwd` 

    M2_HOME=`dirname "$PRG"`/.. 

    # make it fully qualified 
    M2_HOME=`cd "$M2_HOME" && pwd` 
334
readlink -f "$path" 

Chú ý: Các công trình trên với GNUreadlinkFreeBSD/PC-BSD/OpenBSDreadlink, nhưng không trên OS X như của 10.11.
GNUreadlink cung cấp các tùy chọn bổ sung, liên quan, chẳng hạn như -m để giải quyết liên kết tượng trưng cho dù mục tiêu cuối cùng có tồn tại hay không.

Lưu ý vì lõi của GNU 8.15 (2012-01-06), có đường dẫn thực tế chương trình có sẵn ít bị che khuất và linh hoạt hơn so với ở trên. Nó cũng tương thích với tiện ích FreeBSD cùng tên. Nó cũng bao gồm các chức năng để tạo ra một đường dẫn tương đối giữa hai tập tin.

realpath $path 

[Ngoài quản lý dưới đây từ bình luận bằng halloleo - danorton]

Đối với Mac OS X (thông qua ít nhất 10.11.x), sử dụng readlink mà không -f tùy chọn:

readlink $path 

Lưu ý của biên tập viên: Điều này sẽ không giải quyết các liên kết tượng trưng đệ quy và do đó sẽ không báo cáo mục tiêu cuối cùng ; ví dụ., cho liên kết tượng trưng a trỏ đến b, lần lượt trỏ đến c, điều này sẽ chỉ báo cáo b (và sẽ không đảm bảo rằng nó được xuất dưới dạng đường dẫn tuyệt đối).
Sử dụng sau perl lệnh trên OS X để lấp đầy khoảng trống của thiếu readlink -f chức năng:
perl -MCwd -le 'print Cwd::abs_path(shift)' "$path"

+0

tuyệt vời, chính xác những gì tôi cần! – rampion

+5

Tính năng này không hoạt động trong Mac OS X - xem http://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac – Bkkbrad

+1

xấu hổ về OS X không tương thích, nếu không thì tốt đẹp +1 – jkp

11

Một trong những mục yêu thích của tôi là realpath foo

 
realpath - return the canonicalized absolute pathname 

realpath expands all symbolic links and resolves references to '/./', '/../' and extra '/' characters in the null terminated string named by path and 
     stores the canonicalized absolute pathname in the buffer of size PATH_MAX named by resolved_path. The resulting path will have no symbolic link, '/./' or 
     '/../' components. 
+0

Trên Debian (etch và later) lệnh này có sẵn trong gói realpath. –

+1

realpath bây giờ là (tháng 1 năm 2012) là một phần của lõi và tương thích ngược với biến thể debian và BSD – pixelbeat

+1

Tôi không có 'realpath' trên Centos 6 với GNU coreutils 8.4.31. Tôi đã đi qua một số người khác trên [Unix & Linux] (http://unix.stackexchange.com/) có một lõi gói GNU được đóng gói * mà không có * 'realpath'. Vì vậy, nó có vẻ là phụ thuộc vào nhiều hơn chỉ là phiên bản. – toxalot

19

"-P pwd" dường như có tác dụng nếu bạn chỉ muốn thư mục, nhưng nếu vì lý do nào đó bạn muốn tên của tệp thực thi thực tế thì tôi không nghĩ điều đó sẽ hữu ích. Đây là giải pháp của tôi:

#!/bin/bash 

# get the absolute path of the executable 
SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0") 

# resolve symlinks 
while [[ -h $SELF_PATH ]]; do 
    # 1) cd to directory of the symlink 
    # 2) cd to the directory of where the symlink points 
    # 3) get the pwd 
    # 4) append the basename 
    DIR=$(dirname -- "$SELF_PATH") 
    SYM=$(readlink "$SELF_PATH") 
    SELF_PATH=$(cd "$DIR" && cd "$(dirname -- "$SYM")" && pwd)/$(basename -- "$SYM") 
done 
+1

Đây là siêu chuyên nghiệp. Làm tốt. – Zectbumo

4

Một cách khác:

# Gets the real path of a link, following all links 
myreadlink() { [ ! -h "$1" ] && echo "$1" || (local link="$(expr "$(command ls -ld -- "$1")" : '.*-> \(.*\)$')"; cd $(dirname $1); myreadlink "$link" | sed "s|^\([^/].*\)\$|$(dirname $1)/\1|"); } 

# Returns the absolute path to a command, maybe in $PATH (which) or not. If not found, returns the same 
whereis() { echo $1 | sed "s|^\([^/].*/.*\)|$(pwd)/\1|;s|^\([^/]*\)$|$(which -- $1)|;s|^$|$1|"; } 

# Returns the realpath of a called command. 
whereis_realpath() { local SCRIPT_PATH=$(whereis $1); myreadlink ${SCRIPT_PATH} | sed "s|^\([^/].*\)\$|$(dirname ${SCRIPT_PATH})/\1|"; } 
+0

Điều này đã được làm sạch và hoạt động trên OSX. – Alexar

+0

Bạn cần 'cd'and' sed' trong 'myreadlink()' là gì? – jarno

+0

Tôi cần cd trong myreadlink(), bởi vì nó là một hàm đệ quy, đi tới mỗi thư mục cho đến khi nó tìm thấy một liên kết.Nếu nó tìm thấy một liên kết, trả về đường dẫn, và sau đó sed sẽ thay thế đường dẫn. – Keymon

1
function realpath { 
    local r=$1; local t=$(readlink $r) 
    while [ $t ]; do 
     r=$(cd $(dirname $r) && cd $(dirname $t) && pwd -P)/$(basename $t) 
     t=$(readlink $r) 
    done 
    echo $r 
} 

#example usage 
SCRIPT_PARENT_DIR=$(dirname $(realpath "$0"))/.. 
+0

Điều này sẽ phá vỡ với (a) bất kỳ đường dẫn nào chứa khoảng trống hoặc siêu ký tự shell và (b) các liên kết bị hỏng (không phải là vấn đề nếu bạn chỉ muốn đường dẫn cha của tập lệnh đang chạy, giả sử (a) không áp dụng). – mklement0

+0

Nếu bạn quan tâm đến dấu ngoặc kép sử dụng khoảng trống. – Dave

+0

Hãy làm - mặc dù điều đó sẽ không giải quyết (b). – mklement0

1

Để làm việc xung quanh không tương thích Mac, tôi đã đưa ra

echo `php -r "echo realpath('foo');"` 

Không lớn nhưng quả tạt OS

+3

Python 2.6+ có sẵn trên nhiều hệ thống người dùng cuối hơn php, do đó, 'python -c" từ đường dẫn nhập khẩu os; print (path.realpath ('$ {SYMLINK_PATH}')); "' có thể sẽ có ý nghĩa hơn. Tuy nhiên, vào thời điểm bạn cần sử dụng Python từ một kịch bản lệnh shell, có lẽ bạn chỉ nên sử dụng Python và lưu bản thân sự đau đầu của kịch bản lệnh shell nền tảng chéo. –

+0

Bạn không cần nhiều hơn liên kết đọc, tên dir và tên cơ sở. – Dave

+0

@Dave: 'dirname',' basename' và 'readlink' là _utilities_ bên ngoài, không phải shell built-in; 'dirname' và' basename' là một phần của POSIX, 'readlink' thì không. – mklement0

1

Hãy thử cách này:

cd $(dirname $([ -L $0 ] && readlink -f $0 || echo $0)) 
+1

Không hoạt động trên OSX –

1

Kể từ khi tôi đã chạy vào điều này nhiều lần trong những năm qua, và khoảng thời gian này tôi đang rất cần một phiên bản bash tinh khiết xách tay mà tôi có thể sử dụng trên OSX và Linux, tôi đã đi trước và đã viết một:

phiên bản sống sống ở đây:

https://github.com/keen99/shell-functions/tree/master/resolve_path

nhưng vì lợi ích của SO, đây là phiên bản hiện tại (tôi cảm thấy nó cũng tested..but tôi mở cửa cho thông tin phản hồi!)

Có thể không khó để làm cho nó làm việc cho vỏ bourne trơn (sh), nhưng tôi đã không cố gắng ... Tôi thích $ FUNCNAME quá nhiều. :)

#!/bin/bash 

resolve_path() { 
    #I'm bash only, please! 
    # usage: resolve_path <a file or directory> 
    # follows symlinks and relative paths, returns a full real path 
    # 
    local owd="$PWD" 
    #echo "$FUNCNAME for $1" >&2 
    local opath="$1" 
    local npath="" 
    local obase=$(basename "$opath") 
    local odir=$(dirname "$opath") 
    if [[ -L "$opath" ]] 
    then 
    #it's a link. 
    #file or directory, we want to cd into it's dir 
     cd $odir 
    #then extract where the link points. 
     npath=$(readlink "$obase") 
     #have to -L BEFORE we -f, because -f includes -L :(
     if [[ -L $npath ]] 
     then 
     #the link points to another symlink, so go follow that. 
      resolve_path "$npath" 
      #and finish out early, we're done. 
      return $? 
      #done 
     elif [[ -f $npath ]] 
     #the link points to a file. 
     then 
      #get the dir for the new file 
      nbase=$(basename $npath) 
      npath=$(dirname $npath) 
      cd "$npath" 
      ndir=$(pwd -P) 
      retval=0 
      #done 
     elif [[ -d $npath ]] 
     then 
     #the link points to a directory. 
      cd "$npath" 
      ndir=$(pwd -P) 
      retval=0 
      #done 
     else 
      echo "$FUNCNAME: ERROR: unknown condition inside link!!" >&2 
      echo "opath [[ $opath ]]" >&2 
      echo "npath [[ $npath ]]" >&2 
      return 1 
     fi 
    else 
     if ! [[ -e "$opath" ]] 
     then 
      echo "$FUNCNAME: $opath: No such file or directory" >&2 
      return 1 
      #and break early 
     elif [[ -d "$opath" ]] 
     then 
      cd "$opath" 
      ndir=$(pwd -P) 
      retval=0 
      #done 
     elif [[ -f "$opath" ]] 
     then 
      cd $odir 
      ndir=$(pwd -P) 
      nbase=$(basename "$opath") 
      retval=0 
      #done 
     else 
      echo "$FUNCNAME: ERROR: unknown condition outside link!!" >&2 
      echo "opath [[ $opath ]]" >&2 
      return 1 
     fi 
    fi 
    #now assemble our output 
    echo -n "$ndir" 
    if [[ "x${nbase:=}" != "x" ]] 
    then 
     echo "/$nbase" 
    else 
     echo 
    fi 
    #now return to where we were 
    cd "$owd" 
    return $retval 
} 

đây là một ví dụ điển hình, nhờ pha:

%% ls -l `which mvn` 
lrwxr-xr-x 1 draistrick 502 29 Dec 17 10:50 /usr/local/bin/[email protected] -> ../Cellar/maven/3.2.3/bin/mvn 

sử dụng chức năng này và nó sẽ trở lại con đường -real-:

%% cat test.sh 
#!/bin/bash 
. resolve_path.inc 
echo 
echo "relative symlinked path:" 
which mvn 
echo 
echo "and the real path:" 
resolve_path `which mvn` 


%% test.sh 

relative symlinked path: 
/usr/local/bin/mvn 

and the real path: 
/usr/local/Cellar/maven/3.2.3/libexec/bin/mvn 
+0

Câu trả lời trước của tôi thực hiện chính xác điều tương tự trong khoảng 1/4 không gian :) Đó là kịch bản shell khá cơ bản và không xứng đáng với một repo git. – Dave

9
readlink -e [filepath] 

dường như chính xác những gì bạn đang yêu cầu cho - nó chấp nhận một đường dẫn arbirary, giải quyết tất cả các liên kết tượng trưng và trả về đường dẫn "thực" - và đó là "tiêu chuẩn * nix" rằng có khả năng tất cả các hệ thống đã có

2

Lưu ý: Tôi tin rằng đây là một, di động, làm sẵn giải pháp vững chắc, đó là luôn dài cho rằng lý do rất.

Dưới đây là một kịch bản hoàn toàn POSIX-compliant/chức năng đó là do cross-platform (hoạt động trên hệ điều hành MacOS quá, mà readlink vẫn không hỗ trợ -f lúc 10.12 (Sierra)) - nó chỉ sử dụng POSIX shell language features và chỉ các cuộc gọi tiện ích tuân thủ POSIX.

Đây là triển khai di động của GNU readlink -e (phiên bản chặt chẽ của readlink -f).

Bạn có thể chạy kịch bản với sh hoặc nguồn chức năng trong bash, ksh, và zsh:

Ví dụ, bên trong một kịch bản mà bạn có thể sử dụng nó như sau để có được thư mục gốc thực sự của tập lệnh chạy, với các liên kết tượng trưng được giải quyết:

trueScriptDir=$(dirname -- "$(rreadlink "$0")") 

rreadlink script/chức năng định nghĩa:

Mã này đã được chuyển thể với lòng biết ơn từ this answer.
Tôi cũng đã tạo một phiên bản tiện ích độc lập bash dựa trên here, mà bạn có thể cài đặt với
npm install rreadlink -g, nếu bạn đã cài đặt Node.js.

#!/bin/sh 

# SYNOPSIS 
# rreadlink <fileOrDirPath> 
# DESCRIPTION 
# Resolves <fileOrDirPath> to its ultimate target, if it is a symlink, and 
# prints its canonical path. If it is not a symlink, its own canonical path 
# is printed. 
# A broken symlink causes an error that reports the non-existent target. 
# LIMITATIONS 
# - Won't work with filenames with embedded newlines or filenames containing 
#  the string ' -> '. 
# COMPATIBILITY 
# This is a fully POSIX-compliant implementation of what GNU readlink's 
# -e option does. 
# EXAMPLE 
# In a shell script, use the following to get that script's true directory of origin: 
#  trueScriptDir=$(dirname -- "$(rreadlink "$0")") 
rreadlink() (# Execute the function in a *subshell* to localize variables and the effect of `cd`. 

    target=$1 fname= targetDir= CDPATH= 

    # Try to make the execution environment as predictable as possible: 
    # All commands below are invoked via `command`, so we must make sure that 
    # `command` itself is not redefined as an alias or shell function. 
    # (Note that command is too inconsistent across shells, so we don't use it.) 
    # `command` is a *builtin* in bash, dash, ksh, zsh, and some platforms do not 
    # even have an external utility version of it (e.g, Ubuntu). 
    # `command` bypasses aliases and shell functions and also finds builtins 
    # in bash, dash, and ksh. In zsh, option POSIX_BUILTINS must be turned on for 
    # that to happen. 
    { \unalias command; \unset -f command; } >/dev/null 2>&1 
    [ -n "$ZSH_VERSION" ] && options[POSIX_BUILTINS]=on # make zsh find *builtins* with `command` too. 

    while :; do # Resolve potential symlinks until the ultimate target is found. 
     [ -L "$target" ] || [ -e "$target" ] || { command printf '%s\n' "ERROR: '$target' does not exist." >&2; return 1; } 
     command cd "$(command dirname -- "$target")" # Change to target dir; necessary for correct resolution of target path. 
     fname=$(command basename -- "$target") # Extract filename. 
     [ "$fname" = '/' ] && fname='' # !! curiously, `basename /` returns '/' 
     if [ -L "$fname" ]; then 
     # Extract [next] target path, which may be defined 
     # *relative* to the symlink's own directory. 
     # Note: We parse `ls -l` output to find the symlink target 
     #  which is the only POSIX-compliant, albeit somewhat fragile, way. 
     target=$(command ls -l "$fname") 
     target=${target#* -> } 
     continue # Resolve [next] symlink target. 
     fi 
     break # Ultimate target reached. 
    done 
    targetDir=$(command pwd -P) # Get canonical dir. path 
    # Output the ultimate target's canonical path. 
    # Note that we manually resolve paths ending in /. and /.. to make sure we have a normalized path. 
    if [ "$fname" = '.' ]; then 
    command printf '%s\n' "${targetDir%/}" 
    elif [ "$fname" = '..' ]; then 
    # Caveat: something like /var/.. will resolve to /private (assuming /[email protected] -> /private/var), i.e. the '..' is applied 
    # AFTER canonicalization. 
    command printf '%s\n' "$(command dirname -- "${targetDir}")" 
    else 
    command printf '%s\n' "${targetDir%/}/$fname" 
    fi 
) 

rreadlink "[email protected]" 

Một tiếp tuyến về an ninh:

jarno, khi đề cập đến chức năng đảm bảo rằng BUILTIN command không lu mờ bởi một bí danh hoặc vỏ chức năng cùng tên, yêu cầu trong một nhận xét:

Điều gì xảy ra nếu unalias hoặc unset[ được đặt làm bí danh hoặc hàm vỏ?

Động cơ đằng sau rreadlink đảm bảo rằng command có ý nghĩa ban đầu của nó là sử dụng nó để bỏ qua (lành tính) tiện bí danh và chức năng thường được sử dụng để shadow lệnh tiêu chuẩn trong vỏ tương tác, chẳng hạn như xác định lại ls bao gồm tùy chọn ưa thích .

Tôi nghĩ đó là an toàn để nói rằng trừ khi bạn đang làm việc với một môi trường tin cậy, độc hại, lo lắng về unalias hoặc unset - hoặc, cho rằng vấn đề, while, do ... - được định nghĩa lại không phải là một mối quan tâm.

một cái gì đó rằng chức năng phải dựa vào để có ý nghĩa và hành vi ban đầu của nó - không có cách nào xung quanh điều đó.
Vỏ giống POSIX này cho phép định nghĩa lại nội trang và thậm chí từ khóa ngôn ngữ là vốn dĩ là nguy cơ bảo mật (và viết mã hoang tưởng nói chung là khó).

Để giải quyết mối quan tâm của bạn đặc biệt:

Chức năng dựa vào unaliasunset có ý nghĩa ban đầu của họ. Có chúng được định nghĩa lại là các hàm vỏ theo cách làm thay đổi hành vi của chúng sẽ là một vấn đề; định nghĩa lại là một bí danh là không nhất thiết phải là mối quan ngại, bởi vì trích dẫn (một phần) tên lệnh (ví dụ: \unalias) bỏ qua bí danh.

Tuy nhiên, trích dẫn là không một lựa chọn cho vỏ từ khóa (while, for, if, do, ...) và trong khi từ khóa vỏ làm được ưu tiên hơn vỏ chức năng, trong bashzsh bí danh có ưu tiên cao nhất, do đó, để bảo vệ chống lại định nghĩa lại từ khóa shell, bạn phải chạy unalias với tên của chúng (mặc dù trong không tương tácbash vỏ (chẳng hạn như tập lệnh) bí danh là không mở rộng theo mặc định - chỉ khi shopt -s expand_aliases được gọi trước tiên).

Để đảm bảo rằng unalias - như một dựng sẵn - có ý nghĩa ban đầu của nó, bạn phải sử dụng \unset vào nó đầu tiên, đòi hỏi rằng unset có ý nghĩa ban đầu của nó:

unset là một vỏ BUILTIN, vì vậy để đảm bảo rằng nó được gọi như vậy, bạn phải đảm bảo rằng chính nó không được định nghĩa lại là một hàm . Trong khi bạn có thể bỏ qua một biểu mẫu bí danh có trích dẫn, bạn không thể bỏ qua một biểu mẫu hàm vỏ - bắt 22.

Do đó, trừ khi bạn có thể dựa vào ý nghĩa ban đầu của nó, từ những gì tôi có thể nói, không có bảo đảm cách để bảo vệ chống lại tất cả các định nghĩa lại độc hại.

+0

Theo kinh nghiệm của tôi, trích dẫn các bí danh bỏ qua, không phải chức năng của trình bao, không giống như lần đầu tiên bạn nói. – jarno

+0

Tôi đã thử nghiệm rằng tôi có thể định nghĩa '[' như một bí danh trong 'dấu gạch ngang' và' bash' và như một hàm hệ vỏ trong 'bash'. – jarno

+1

Tôi đã đặt điểm của mình thành [câu hỏi] riêng biệt (http://stackoverflow.com/q/35916983/4414935). – jarno

5

Đưa một số giải pháp đã cho cùng với nhau, biết rằng có sẵn liên kết đọc trên hầu hết các hệ thống, nhưng cần các đối số khác nhau, điều này hoạt động tốt đối với tôi trên OSX và Debian. Tôi không chắc chắn về các hệ thống BSD. Có thể điều kiện cần phải là [[ $OSTYPE != darwin* ]] để loại trừ -f chỉ từ OSX.

#!/bin/bash 
MY_DIR=$(cd $(dirname $(readlink `[[ $OSTYPE == linux* ]] && echo "-f"` $0)) ; pwd -P) 
echo "$MY_DIR" 
0

Tôi tin rằng đây là "cách để giải quyết một liên kết tượng trưng" true và dứt khoát cho dù đó là một thư mục hoặc một tổ chức phi thư mục, sử dụng Bash:

function readlinks {(
    set -o errexit -o nounset 
    declare n=0 limit=1024 link="$1" 

    # If it's a directory, just skip all this. 
    if cd "$link" 2>/dev/null 
    then 
    pwd -P "$link" 
    return 0 
    fi 

    # Resolve until we are out of links (or recurse too deep). 
    while [[ -L $link ]] && [[ $n -lt $limit ]] 
    do 
    cd "$(dirname -- "$link")" 
    n=$((n + 1)) 
    link="$(readlink -- "${link##*/}")" 
    done 
    cd "$(dirname -- "$link")" 

    if [[ $n -ge $limit ]] 
    then 
    echo "Recursion limit ($limit) exceeded." >&2 
    return 2 
    fi 

    printf '%s/%s\n' "$(pwd -P)" "${link##*/}" 
)} 

Lưu ý rằng tất cả các cdset công cụ diễn ra trong một subshell.

+0

Trên thực tế, {} quanh() là không cần thiết, vì() được tính là một "lệnh ghép", giống như {}. Nhưng bạn vẫn cần() sau tên hàm. –

0

Sau đây là cách người ta có thể có được con đường thực tế để các tập tin trong hệ điều hành MacOS/Unix sử dụng inline Perl script:

FILE=$(perl -e "use Cwd qw(abs_path); print abs_path('$0')") 

Tương tự như vậy, để có được những thư mục của một tập tin symlinked:

DIR=$(perl -e "use Cwd qw(abs_path); use File::Basename; print dirname(abs_path('$0'))") 
Các vấn đề liên quan