Có một lệnh để lấy đường dẫn tuyệt đối cho đường dẫn tương đối không?
Ví dụ: tôi muốn $ line chứa đường dẫn tuyệt đối của mỗi tệp trong thư mục ./etc/
find ./ -type f | while read line; do
echo $line
done
Có một lệnh để lấy đường dẫn tuyệt đối cho đường dẫn tương đối không?
Ví dụ: tôi muốn $ line chứa đường dẫn tuyệt đối của mỗi tệp trong thư mục ./etc/
find ./ -type f | while read line; do
echo $line
done
Câu trả lời:
sử dụng:
find "$(pwd)"/ -type f
để có được tất cả các tập tin hoặc
echo "$(pwd)/$line"
để hiển thị đường dẫn đầy đủ (nếu đường dẫn tương đối quan trọng)
$(pwd)
thay $PWD
thế? (vâng, tôi biết pwd
là một nội dung)
Hãy thử realpath
.
~ $ sudo apt-get install realpath # may already be installed
~ $ realpath .bashrc
/home/username/.bashrc
Để tránh mở rộng liên kết tượng trưng, sử dụng realpath -s
.
Câu trả lời đến từ " lệnh bash / fish để in đường dẫn tuyệt đối đến một tệp ".
realpath
dường như không khả dụng trên Mac (OS X 10.11 "El Capitan"). :-(
realpath
dường như cũng không khả dụng trên CentOS 6
brew install coreutils
sẽ mang vàorealpath
realpath
đã có mặt. Tôi đã không phải cài đặt nó một cách riêng biệt.
realpath
có sẵn trên Git cho Windows (ít nhất là đối với tôi).
Nếu bạn đã cài đặt gói coreutils, bạn thường có thể sử dụng readlink -f relative_file_name
để truy xuất gói tuyệt đối (với tất cả các liên kết tượng trưng được giải quyết)
brew install coreutils
. Tuy nhiên, việc thực thi được chuẩn bị bởi ag:greadlink -f relative_file_name
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
CẬP NHẬT Một số giải thích
"$1"
dirname "$1"
cd "$(dirname "$1")
vào thư mục tương đối này và nhận đường dẫn tuyệt đối cho nó bằng cách chạy pwd
lệnh shell$(basename "$1")
echo
nórealpath
hoặc readlink -f
làm. Chẳng hạn, nó không hoạt động trên các đường dẫn trong đó thành phần cuối cùng là một liên kết tượng trưng.
-P
tùy chọn để ra pwd
lệnh:echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"
Đối với những gì nó có giá trị, tôi đã bỏ phiếu cho câu trả lời đã được chọn, nhưng muốn chia sẻ một giải pháp. Nhược điểm là, chỉ có Linux - Tôi đã dành khoảng 5 phút để cố gắng tìm OSX tương đương trước khi đến với Stack tràn. Tôi chắc chắn rằng nó ở ngoài đó mặc dù.
Trên Linux, bạn có thể sử dụng readlink -e
song song với dirname
.
$(dirname $(readlink -e ../../../../etc/passwd))
sản lượng
/etc/
Và sau đó bạn sử dụng dirname
chị gái, basename
để chỉ lấy tên tệp
$(basename ../../../../../passwd)
sản lượng
passwd
Đặt nó tất cả cùng nhau..
F=../../../../../etc/passwd
echo "$(dirname $(readlink -e $F))/$(basename $F)"
sản lượng
/etc/passwd
Bạn an toàn nếu bạn đang nhắm mục tiêu một thư mục, basename
sẽ không trả lại bất cứ thứ gì và bạn sẽ kết thúc bằng dấu gạch chéo kép ở đầu ra cuối cùng.
dirname
, readlink
, và basename
. Điều đó giúp tôi có được đường dẫn tuyệt đối của một liên kết tượng trưng - không phải mục tiêu của nó.
/home/GKFX
và tôi gõ touch newfile
, thì trước khi tôi nhấn, bạn có thể hiểu rằng tôi có nghĩa là "tạo / nhà / GKFX / newfile", đây là một đường dẫn tuyệt đối đến một tệp chưa tồn tại.
Tôi nghĩ rằng đây là di động nhất:
abspath() {
cd "$(dirname "$1")"
printf "%s/%s\n" "$(pwd)" "$(basename "$1")"
cd "$OLDPWD"
}
Nó sẽ thất bại nếu đường dẫn không tồn tại mặc dù.
dirname
là một tiện ích lõi GNU, không phổ biến đối với tất cả các unixen tôi tin.
dirname
là một tiện ích tiêu chuẩn POSIX, xem tại đây: pubs.opengroup.org/onlinepub/9699919799/utilities/dirname.html
${1##*/}
trong một ngày và bây giờ tôi đã thay thế thùng rác basename "$1"
đó bằng cách cuối cùng có thể xử lý đúng các đường dẫn kết thúc bằng /.
../..
realpath
có lẽ là tốt nhất
Nhưng ...
Câu hỏi ban đầu rất bối rối khi bắt đầu, với một ví dụ liên quan đến câu hỏi như đã nêu.
Câu trả lời được chọn thực sự trả lời ví dụ đã cho, và hoàn toàn không phải câu hỏi trong tiêu đề. Lệnh đầu tiên là câu trả lời đó (có thực sự không? Tôi nghi ngờ), và có thể làm tốt mà không cần '/'. Và tôi không thấy lệnh thứ hai đang làm gì.
Một số vấn đề được trộn lẫn:
thay đổi một tên đường dẫn tương đối thành một tên tuyệt đối, bất kể nó biểu thị điều gì, có thể không có gì. ( Thông thường, nếu bạn ban hành một lệnh như touch foo/bar
, tên đường dẫn foo/bar
phải tồn tại cho bạn và có thể được sử dụng trong tính toán, trước khi tệp thực sự được tạo. )
có thể có một số tên đường dẫn tuyệt đối biểu thị cùng một tệp (hoặc tệp tiềm năng), đáng chú ý là do các liên kết tượng trưng (symlink) trên đường dẫn, nhưng có thể vì các lý do khác (một thiết bị có thể được gắn hai lần chỉ đọc). Người ta có thể hoặc không muốn giải quyết các liên kết như vậy.
đi đến cuối chuỗi các liên kết tượng trưng đến một tệp hoặc tên không liên kết. Điều này có thể hoặc không thể mang lại một tên đường dẫn tuyệt đối, tùy thuộc vào cách nó được thực hiện. Và người ta có thể, hoặc có thể không muốn giải quyết nó thành một tên đường dẫn tuyệt đối.
Lệnh readlink foo
không có tùy chọn chỉ đưa ra câu trả lời nếu đối số của nó foo
là liên kết tượng trưng và câu trả lời đó là giá trị của liên kết tượng trưng đó. Không có liên kết khác được theo sau. Câu trả lời có thể là một đường dẫn tương đối: bất cứ giá trị nào của đối số symlink.
Tuy nhiên, readlink
có các tùy chọn (-f -e hoặc -m) sẽ hoạt động cho tất cả các tệp và đặt một tên đường dẫn tuyệt đối (tên không có liên kết tượng trưng) cho tệp thực sự được biểu thị bằng đối số.
Điều này hoạt động tốt cho bất cứ điều gì không phải là một liên kết tượng trưng, mặc dù người ta có thể muốn sử dụng một tên đường dẫn tuyệt đối mà không giải quyết các liên kết trung gian trên đường dẫn. Điều này được thực hiện bởi lệnhrealpath -s foo
Trong trường hợp đối số symlink, readlink
với các tùy chọn của nó sẽ lại giải quyết tất cả các liên kết tượng trưng trên đường dẫn tuyệt đối đến đối số, nhưng điều đó cũng sẽ bao gồm tất cả các liên kết tượng trưng có thể gặp phải bằng cách tuân theo giá trị đối số. Bạn có thể không muốn rằng nếu bạn muốn một đường dẫn tuyệt đối đến chính liên kết đối số, hơn là bất cứ điều gì nó có thể liên kết đến. Một lần nữa, nếu foo
là một liên kết tượng trưng, realpath -s foo
sẽ có được một đường dẫn tuyệt đối mà không giải quyết các liên kết tượng trưng, bao gồm cả một liên kết được đưa ra làm đối số.
Không có -s
tùy chọn, realpath
sẽ thực hiện khá nhiều
readlink
, ngoại trừ việc chỉ đọc giá trị của một liên kết, cũng như một số thứ khác. Nó chỉ không rõ ràng cho tôi tại sao readlink
có các tùy chọn của nó, tạo ra sự dư thừa không mong muốn với
realpath
.
Khám phá web không nói gì nhiều, ngoại trừ việc có thể có một số biến thể trên các hệ thống.
Kết luận: realpath
là lệnh tốt nhất để sử dụng, với tính linh hoạt nhất, ít nhất là cho việc sử dụng được yêu cầu ở đây.
Giải pháp yêu thích của tôi là một bằng @EugenKonkov bởi vì nó không bao hàm sự hiện diện của các tiện ích khác (gói coreutils).
Nhưng nó đã thất bại cho các đường dẫn tương đối "." và "..", vì vậy đây là phiên bản cải tiến nhẹ xử lý các trường hợp đặc biệt này.
Nó vẫn không thành công nếu người dùng không có quyền cd
vào thư mục mẹ của đường dẫn tương đối.
#! /bin/sh
# Takes a path argument and returns it as an absolute path.
# No-op if the path is already absolute.
function to-abs-path {
local target="$1"
if [ "$target" == "." ]; then
echo "$(pwd)"
elif [ "$target" == ".." ]; then
echo "$(dirname "$(pwd)")"
else
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
fi
}
Câu trả lời của Eugen không hoàn toàn phù hợp với tôi nhưng điều này đã làm:
absolute="$(cd $(dirname \"$file\"); pwd)/$(basename \"$file\")"
Lưu ý bên, thư mục làm việc hiện tại của bạn không bị ảnh hưởng.
Giải pháp tốt nhất, imho, là giải pháp được đăng ở đây: https://stackoverflow.com/a/3373298/9724628 .
Nó đòi hỏi python để làm việc, nhưng nó dường như bao gồm tất cả hoặc hầu hết các trường hợp cạnh và là giải pháp rất di động.
python -c "import os,sys; print(os.path.realpath(sys.argv[1]))" path/to/file
python -c "import os,sys; print(os.path.abspath(sys.argv[1]))" path/to/file
Nếu bạn đang sử dụng bash trên Mac OS X mà không phải đã realpath tồn tại và cũng không nó readlink có thể in các đường dẫn tuyệt đối, bạn có thể có lựa chọn nào khác để mã phiên bản của riêng bạn để in nó. Đây là cách thực hiện của tôi:
(bash tinh khiết)
abspath(){
local thePath
if [[ ! "$1" =~ ^/ ]];then
thePath="$PWD/$1"
else
thePath="$1"
fi
echo "$thePath"|(
IFS=/
read -a parr
declare -a outp
for i in "${parr[@]}";do
case "$i" in
''|.) continue ;;
..)
len=${#outp[@]}
if ((len==0));then
continue
else
unset outp[$((len-1))]
fi
;;
*)
len=${#outp[@]}
outp[$len]="$i"
;;
esac
done
echo /"${outp[*]}"
)
}
(sử dụng chim ưng)
abspath_gawk() {
if [[ -n "$1" ]];then
echo $1|gawk '{
if(substr($0,1,1) != "/"){
path = ENVIRON["PWD"]"/"$0
} else path = $0
split(path, a, "/")
n = asorti(a, b,"@ind_num_asc")
for(i in a){
if(a[i]=="" || a[i]=="."){
delete a[i]
}
}
n = asorti(a, b, "@ind_num_asc")
m = 0
while(m!=n){
m = n
for(i=1;i<=n;i++){
if(a[b[i]]==".."){
if(b[i-1] in a){
delete a[b[i-1]]
delete a[b[i]]
n = asorti(a, b, "@ind_num_asc")
break
} else exit 1
}
}
}
n = asorti(a, b, "@ind_num_asc")
if(n==0){
printf "/"
} else {
for(i=1;i<=n;i++){
printf "/"a[b[i]]
}
}
}'
fi
}
(bsd awk thuần túy)
#!/usr/bin/env awk -f
function abspath(path, i,j,n,a,b,back,out){
if(substr(path,1,1) != "/"){
path = ENVIRON["PWD"]"/"path
}
split(path, a, "/")
n = length(a)
for(i=1;i<=n;i++){
if(a[i]==""||a[i]=="."){
continue
}
a[++j]=a[i]
}
for(i=j+1;i<=n;i++){
delete a[i]
}
j=0
for(i=length(a);i>=1;i--){
if(back==0){
if(a[i]==".."){
back++
continue
} else {
b[++j]=a[i]
}
} else {
if(a[i]==".."){
back++
continue
} else {
back--
continue
}
}
}
if(length(b)==0){
return "/"
} else {
for(i=length(b);i>=1;i--){
out=out"/"b[i]
}
return out
}
}
BEGIN{
if(ARGC>1){
for(k=1;k<ARGC;k++){
print abspath(ARGV[k])
}
exit
}
}
{
print abspath($0)
}
thí dụ:
$ abspath I/am/.//..//the/./god/../of///.././war
/Users/leon/I/the/war
Nếu đường dẫn tương đối là đường dẫn thư mục, thì hãy thử của tôi, nên là tốt nhất:
absPath=$(pushd ../SOME_RELATIVE_PATH_TO_Directory > /dev/null && pwd && popd > /dev/null)
echo $absPath
echo "mydir/doc/ mydir/usoe ./mydir/usm" | awk '{ split($0,array," "); for(i in array){ system("cd "array[i]" && echo $PWD") } }'
Một cải tiến cho phiên bản khá hay của @ ernest-a:
absolute_path() {
cd "$(dirname "$1")"
case $(basename $1) in
..) echo "$(dirname $(pwd))";;
.) echo "$(pwd)";;
*) echo "$(pwd)/$(basename $1)";;
esac
}
Điều này xử lý chính xác với trường hợp phần tử cuối cùng của đường dẫn ..
, trong trường hợp đó "$(pwd)/$(basename "$1")"
, câu trả lời trong @ ernest-a sẽ xuất hiện dưới dạng accurate_sub_path/spurious_subdirectory/..
.
Nếu bạn muốn chuyển đổi một biến chứa đường dẫn tương đối thành một đường tuyệt đối, thì điều này hoạt động:
dir=`cd "$dir"`
"cd" lặp lại mà không thay đổi thư mục làm việc, bởi vì được thực hiện ở đây trong một vỏ con.
dir=`cd ".."` && echo $dir
Đây là một giải pháp được xâu chuỗi từ tất cả những người khác, ví dụ, khi realpath
thất bại, vì nó không được cài đặt hoặc vì nó thoát với mã lỗi, sau đó, giải pháp tiếp theo được thử cho đến khi nó đi đúng đường.
#!/bin/bash
function getabsolutepath() {
local target;
local changedir;
local basedir;
local firstattempt;
target="${1}";
if [ "$target" == "." ];
then
printf "%s" "$(pwd)";
elif [ "$target" == ".." ];
then
printf "%s" "$(dirname "$(pwd)")";
else
changedir="$(dirname "${target}")" && basedir="$(basename "${target}")" && firstattempt="$(cd "${changedir}" && pwd)" && printf "%s/%s" "${firstattempt}" "${basedir}" && return 0;
firstattempt="$(readlink -f "${target}")" && printf "%s" "${firstattempt}" && return 0;
firstattempt="$(realpath "${target}")" && printf "%s" "${firstattempt}" && return 0;
# If everything fails... TRHOW PYTHON ON IT!!!
local fullpath;
local pythoninterpreter;
local pythonexecutables;
local pythonlocations;
pythoninterpreter="python";
declare -a pythonlocations=("/usr/bin" "/bin");
declare -a pythonexecutables=("python" "python2" "python3");
for path in "${pythonlocations[@]}";
do
for executable in "${pythonexecutables[@]}";
do
fullpath="${path}/${executable}";
if [[ -f "${fullpath}" ]];
then
# printf "Found ${fullpath}\\n";
pythoninterpreter="${fullpath}";
break;
fi;
done;
if [[ "${pythoninterpreter}" != "python" ]];
then
# printf "Breaking... ${pythoninterpreter}\\n"
break;
fi;
done;
firstattempt="$(${pythoninterpreter} -c "import os, sys; print( os.path.abspath( sys.argv[1] ) );" "${target}")" && printf "%s" "${firstattempt}" && return 0;
# printf "Error: Could not determine the absolute path!\\n";
return 1;
fi
}
printf "\\nResults:\\n%s\\nExit: %s\\n" "$(getabsolutepath "./asdfasdf/ asdfasdf")" "${?}"
Bạn có thể sử dụng thay thế chuỗi bash cho bất kỳ đường dẫn tương đối $ line:
line=$(echo ${line/#..\//`cd ..; pwd`\/})
line=$(echo ${line/#.\//`pwd`\/})
echo $line
Sự thay thế trước chuỗi cơ bản tuân theo công thức
$ {chuỗi / # chuỗi con / thay thế}
được thảo luận tốt ở đây: https://www.tldp.org/LDP/abs/html/opes-manipulation.html
Ký \
tự phủ nhận /
khi chúng ta muốn nó là một phần của chuỗi mà chúng ta tìm / thay thế.
Tôi không thể tìm thấy một giải pháp có thể di động gọn gàng giữa Mac OS Catalina, Ubuntu 16 và Centos 7, vì vậy tôi đã quyết định thực hiện với python inline và nó hoạt động tốt cho các tập lệnh bash của tôi.
to_abs_path() {
python -c "import os; print os.path.abspath('$1')"
}
to_abs_path "/some_path/../secrets"