Miễn là bạn có quyền thực thi trên thư mục hiện tại - hoặc trên thư mục mà bạn đã thực thi tập lệnh shell của mình - nếu bạn muốn một đường dẫn tuyệt đối đến thư mục, tất cả những gì bạn cần là cd
.
Bước 10 của cd
thông số kỹ thuật
Nếu -P
tùy chọn có hiệu lực, $PWD
biến môi trường sẽ được đặt thành chuỗi sẽ được xuất theo pwd -P
. Nếu không có đủ quyền trên thư mục mới hoặc trên bất kỳ cha mẹ nào của thư mục đó, để xác định thư mục làm việc hiện tại, giá trị của $PWD
biến môi trường là không xác định.
Và hơn thế nữa pwd -P
Tên đường dẫn được ghi vào đầu ra tiêu chuẩn sẽ không chứa bất kỳ thành phần nào đề cập đến các tệp có liên kết tượng trưng loại. Nếu có nhiều tên đường dẫn mà pwd
tiện ích có thể ghi vào đầu ra tiêu chuẩn, một bắt đầu bằng một ký tự / dấu gạch chéo và một hoặc nhiều bắt đầu bằng hai / ký tự gạch chéo, thì nó sẽ viết tên đường dẫn bắt đầu bằng một ký tự gạch chéo / đơn. Tên đường dẫn không được chứa bất kỳ ký tự / dấu gạch chéo nào sau một hoặc hai ký tự gạch chéo.
Đó là bởi vì cd -P
có để thiết lập thư mục làm việc hiện tại với những gì pwd -P
khác nên in và rằng cd -
có in $OLDPWD
rằng các công việc sau:
mkdir ./dir
ln -s ./dir ./ln
cd ./ln ; cd . ; cd -
ĐẦU RA
/home/mikeserv/test/ln
chờ đã ...
cd -P . ; cd . ; cd -
ĐẦU RA
/home/mikeserv/test/dir
Và khi tôi in với cd -
tôi đang in $OLDPWD
. cd
thiết lập $PWD
ngay khi tôi cd -P .
$PWD
bây giờ là một đường dẫn tuyệt đối /
- vì vậy tôi không cần bất kỳ biến nào khác. Và trên thực tế, tôi nên thậm chí không cần các dấu .
nhưng có một hành vi cụ thể của thiết lập lại $PWD
để $HOME
trong một vỏ tương tác khi cd
là không trang trí. Vì vậy, nó chỉ là một thói quen tốt để phát triển.
Vì vậy, chỉ cần thực hiện các thao tác trên trên đường dẫn trong ${0%/*}
là quá đủ để xác minh $0
đường dẫn, nhưng trong trường hợp $0
chính nó là một liên kết mềm, có lẽ bạn không thể thay đổi thư mục vào đó.
Đây là một chức năng sẽ xử lý rằng:
zpath() { cd -P . || return
_out() { printf "%s$_zdlm\n" "$PWD/${1##*/}"; }
_cd() { cd -P "$1" ; } >/dev/null 2>&1
while [ $# -gt 0 ] && _cd .
do if _cd "$1"
then _out
elif ! [ -L "$1" ] && [ -e "$1" ]
then _cd "${1%/*}"; _out "$1"
elif [ -L "$1" ]
then ( while set -- "${1%?/}"; _cd "${1%/*}"; [ -L "${1##*/}" ]
do set " $1" "$(_cd -; ls -nd -- "$1"; echo /)"
set -- "${2#*"$1" -> }"
done; _out "$1"
); else ( PS4=ERR:\ NO_SUCH_PATH; set -x; : "$1" )
fi; _cd -; shift; done
unset -f _out _cd; unset -v _zdlm
}
Nó cố gắng làm nhiều nhất có thể trong shell hiện tại - mà không cần gọi một subshell - mặc dù có các subshell được gọi cho các lỗi và các liên kết mềm không trỏ đến các thư mục. Nó phụ thuộc vào lớp vỏ tương thích POSIX và tương thích POSIX ls
cũng như _function()
không gian tên sạch . Nó vẫn sẽ hoạt động tốt mà không cần cái sau, mặc dù nó có thể ghi đè lên unset
một số hàm shell hiện tại trong trường hợp đó. Nhìn chung, tất cả các phụ thuộc này đều có sẵn trên máy Unix.
Được gọi có hoặc không có đối số, điều đầu tiên nó được đặt lại $PWD
thành giá trị chính tắc của nó - nó giải quyết bất kỳ liên kết nào trong đó đến các mục tiêu của chúng khi cần thiết. Được gọi mà không có đối số và đó là về nó; nhưng được gọi với họ và nó sẽ giải quyết và chuẩn hóa đường dẫn cho mỗi hoặc nếu không thì in một tin nhắn stderr
tại sao không.
Bởi vì nó chủ yếu hoạt động trong trình bao hiện tại nên nó có thể xử lý một danh sách đối số có độ dài bất kỳ. Nó cũng tìm kiếm $_zdlm
biến số (cũng unset
là khi nó thông qua) và in giá trị thoát C của nó ngay bên phải mỗi đối số của nó, mỗi đối số luôn được theo sau bởi một \n
ký tự ewline.
Nó thực hiện rất nhiều thay đổi thư mục, nhưng, ngoài việc đặt nó thành giá trị chính tắc của nó, nó không ảnh hưởng $PWD
, mặc dù $OLDPWD
không thể bằng bất kỳ phương tiện nào được tính khi nó đi qua.
Nó cố gắng bỏ từng đối số của nó ngay khi có thể. Đầu tiên nó cố gắng cd
vào $1
. Nếu nó có thể in đường dẫn chính tắc của đối số tới stdout
. Nếu nó không thể kiểm tra nó $1
tồn tại và không phải là một liên kết mềm. Nếu đúng, nó in.
Theo cách này, nó xử lý bất kỳ đối số loại tệp nào mà shell có quyền truy cập trừ khi $1
là một liên kết tượng trưng không trỏ đến một thư mục. Trong trường hợp đó, nó gọi while
vòng lặp trong một subshell.
Nó gọi ls
để đọc liên kết. Thư mục hiện tại phải được thay đổi thành giá trị ban đầu trước tiên để xử lý một cách đáng tin cậy bất kỳ đường dẫn tham chiếu nào và do đó, trong lệnh thay thế lệnh con, hàm này thực hiện:
cd -...ls...echo /
Nó thoát khỏi bên trái của ls
đầu ra ít nhất là phải chứa đầy đủ tên và chuỗi của liên kết ->
. Lúc đầu tôi đã cố gắng tránh làm điều này với shift
và $IFS
hóa ra đây là phương pháp đáng tin cậy nhất gần như tôi có thể hình dung. Đây là điều tương tự poor_mans_readlink của Gilles - và nó được thực hiện tốt.
Nó sẽ lặp lại quá trình này trong một vòng lặp cho đến khi tên tệp được trả về ls
chắc chắn không phải là một liên kết mềm. Tại thời điểm đó, nó chuẩn hóa đường dẫn đó như trước với cd
sau đó in.
Ví dụ sử dụng:
zpath \
/tmp/script \ #symlink to $HOME/test/dir/script.sh
ln \ #symlink to ./dir/
ln/nl \ #symlink to ../..
/dev/fd/0 \ #currently a here-document like : dash <<\HD
/dev/fd/1 \ #(zlink) | dash
file \ #regular file
doesntexist \ #doesnt exist
/dev/disk/by-path/pci-0000:00:16.2-usb-0:3:1.0-scsi-0:0:0:0 \
/dev/./././././././null \
. ..
ĐẦU RA
/home/mikeserv/test/dir/script.sh
/home/mikeserv/test/dir/
/home/mikeserv/test/
/tmp/zshtpKRVx (deleted)
/proc/17420/fd/pipe:[1782312]
/home/mikeserv/test/file
ERR: NO_SUCH_PATH: doesntexist
/dev/sdd
/dev/null
/home/mikeserv/test/
/home/mikeserv/
Hoặc có thể ...
ls
dir/ file file? folder/ link@ ln@ script* script3@ script4@
zdlm=\\0 zpath * | cat -A
ĐẦU RA
/home/mikeserv/test/dir/^@$
/home/mikeserv/test/file^@$
/home/mikeserv/test/file$
^@$
/home/mikeserv/test/folder/^@$
/home/mikeserv/test/file$ #'link' -> 'file\n'
^@$
/home/mikeserv/test/dir/^@$ #'ln' -> './dir'
/home/mikeserv/test/script^@$
/home/mikeserv/test/dir/script.sh^@$ #'script3' -> './dir/script.sh'
/home/mikeserv/test/dir/script.sh^@$ #'script4' -> '/tmp/script' -> ...