क्या सापेक्ष पथ को देखते हुए निरपेक्ष मार्ग को पुनः प्राप्त करने की आज्ञा है?
उदाहरण के लिए मैं dir में प्रत्येक फ़ाइल के पूर्ण पथ को शामिल करने के लिए $ लाइन चाहता हूं ./etc/
find ./ -type f | while read line; do
echo $line
done
क्या सापेक्ष पथ को देखते हुए निरपेक्ष मार्ग को पुनः प्राप्त करने की आज्ञा है?
उदाहरण के लिए मैं dir में प्रत्येक फ़ाइल के पूर्ण पथ को शामिल करने के लिए $ लाइन चाहता हूं ./etc/
find ./ -type f | while read line; do
echo $line
done
जवाबों:
उपयोग:
find "$(pwd)"/ -type f
सभी फ़ाइलों को पाने के लिए या
echo "$(pwd)/$line"
पूर्ण पथ प्रदर्शित करने के लिए (यदि सापेक्ष पथ मायने रखता है)
$(pwd)
स्थान पर क्यों उपयोग करें $PWD
? (हां, मुझे पता pwd
है कि एक बिलियन है)
कोशिश करो realpath
।
~ $ sudo apt-get install realpath # may already be installed
~ $ realpath .bashrc
/home/username/.bashrc
सीमलिंक के विस्तार से बचने के लिए, का उपयोग करें realpath -s
।
इसका उत्तर " bash / फिश कमांड से फाइल में पूर्ण पथ प्रिंट करने के लिए " आता है ।
realpath
मैक (OS X 10.11 "El Capitan") पर उपलब्ध नहीं लगता है। :-(
realpath
CentOS 6 पर उपलब्ध नहीं लगता है
brew install coreutils
में लाना होगाrealpath
realpath
पहले से मौजूद है। मुझे इसे अलग से स्थापित करने की आवश्यकता नहीं थी।
realpath
विंडोज के लिए गिट पर उपलब्ध है (मेरे लिए, कम से कम)।
यदि आपके पास कोरुटिल्स पैकेज स्थापित है, तो आप आम तौर पर readlink -f relative_file_name
निरपेक्ष एक को पुनः प्राप्त करने के लिए उपयोग कर सकते हैं (सभी सिमिलिंक के साथ हल)
brew install coreutils
। हालाँकि निष्पादन योग्य एजी द्वारा प्रीपेड किया गया है:greadlink -f relative_file_name
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
UPD कुछ स्पष्टीकरण
"$1"
dirname "$1"
cd "$(dirname "$1")
इस सापेक्ष डायर में जाते हैं और pwd
शेल कमांड चलाकर इसके लिए पूर्ण मार्ग प्राप्त करते हैं$(basename "$1")
echo
इसेrealpath
या क्या करने के बराबर नहीं readlink -f
है। उदाहरण के लिए, यह उन रास्तों पर काम नहीं करता है जहाँ अंतिम घटक एक सिम्लिंक है।
-P
को विकल्प प्रदान कर सकते हैं pwd
:echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"
इसके लायक क्या है, मैंने उस उत्तर के लिए मतदान किया था जिसे चुना गया था, लेकिन एक समाधान साझा करना चाहता था। नकारात्मक पक्ष यह है, यह केवल लिनक्स है - मैंने स्टैक ओवरफ्लो आने से पहले ओएसएक्स को खोजने के लिए लगभग 5 मिनट का समय बिताया। मुझे यकीन है कि यह वहाँ से बाहर है, हालांकि।
लिनक्स पर आप readlink -e
के साथ मिलकर उपयोग कर सकते हैं dirname
।
$(dirname $(readlink -e ../../../../etc/passwd))
पैदावार
/etc/
और फिर आप केवल फ़ाइल नाम प्राप्त करने के लिए dirname
, बहन का उपयोग basename
करते हैं
$(basename ../../../../../passwd)
पैदावार
passwd
इसे एक साथ रखें..
F=../../../../../etc/passwd
echo "$(dirname $(readlink -e $F))/$(basename $F)"
पैदावार
/etc/passwd
यदि आप किसी निर्देशिका को लक्षित कर रहे हैं तो आप सुरक्षित हैं, basename
कुछ भी नहीं लौटाएंगे और आप अंतिम आउटपुट में डबल स्लैश के साथ समाप्त हो जाएंगे।
dirname
, readlink
, और basename
। इससे मुझे एक प्रतीकात्मक कड़ी का पूर्ण मार्ग प्राप्त करने में मदद मिली - इसका लक्ष्य नहीं।
/home/GKFX
और टाइप करता हूं touch newfile
, तो इससे पहले कि मैं एंटर करता हूं आप वर्कआउट कर सकते हैं कि मेरा मतलब है "create / home / GKFX / newfile", जो एक फाइल का एक पूर्ण पथ है जो अभी तक मौजूद नहीं है।
मुझे लगता है कि यह सबसे पोर्टेबल है:
abspath() {
cd "$(dirname "$1")"
printf "%s/%s\n" "$(pwd)" "$(basename "$1")"
cd "$OLDPWD"
}
यदि मार्ग मौजूद नहीं है, तो यह विफल हो जाएगा।
dirname
एक जीएनयू कोर उपयोगिता है, जो मुझे विश्वास नहीं है कि सभी यूनिक्स के लिए आम है।
dirname
एक POSIX मानक उपयोगिता है, यहां देखें: pubs.opengroup.org/onlinepubs/9699919799/utilities/dirname.html
${1##*/}
अब एक दिन के लिए उपयोग करता है , और अब जब मैंने उस कचरे को बदल दिया, basename "$1"
तो लगता है कि अंत में / में समाप्त होने वाले रास्तों को ठीक से संभालना होगा।
../..
realpath
शायद सबसे अच्छा है
परंतु ...
प्रारंभिक प्रश्न के साथ शुरू करने के लिए बहुत उलझन में था, उदाहरण के लिए कहा गया सवाल से संबंधित खराब।
चयनित उत्तर वास्तव में दिए गए उदाहरण का उत्तर देता है, और शीर्षक में सभी प्रश्न पर नहीं। पहला आदेश वह उत्तर है (क्या यह वास्तव में है? मुझे संदेह है), और '/' के बिना भी कर सकता है। और मैं यह देखने में विफल हूं कि दूसरा आदेश क्या कर रहा है।
कई मुद्दे मिश्रित हैं:
एक सापेक्ष पथनाम को एक पूर्ण में बदलना, जो भी इसे दर्शाता है, संभवतः कुछ भी नहीं। ( आमतौर पर, यदि आप एक कमांड जारी करते हैं जैसे कि touch foo/bar
, पथनाम foo/bar
आपके लिए मौजूद होना चाहिए, और संभवतः गणना में उपयोग किया जाना चाहिए, इससे पहले कि फ़ाइल वास्तव में बनाई जाए। )
ऐसे कई निरपेक्ष पथनाम हो सकते हैं जो समान फ़ाइल (या संभावित फ़ाइल) को दर्शाते हैं, विशेष रूप से पथ पर प्रतीकात्मक लिंक (सिमिलिंक) के कारण, लेकिन संभवतः अन्य कारणों से (एक डिवाइस को केवल-पढ़ने के लिए दो बार माउंट किया जा सकता है)। कोई भी इस तरह की सहानुभूति की खोज को हल करना चाहता है या नहीं कर सकता है।
एक गैर-सिमलिंक फ़ाइल या नाम के लिए प्रतीकात्मक लिंक की एक श्रृंखला के अंत में जाना। यह कैसे किया जाता है, इस पर निर्भर करते हुए एक निरपेक्ष पथ नाम प्राप्त कर सकता है या नहीं। और एक, या एक निरपेक्ष पथनाम में इसे हल नहीं करना चाह सकता है।
readlink foo
विकल्प के बिना कमांड केवल एक उत्तर देता है यदि उसका तर्क foo
एक प्रतीकात्मक लिंक है, और यह उत्तर उस सिम्कलिन का मूल्य है। किसी अन्य लिंक का पालन नहीं किया जाता है। उत्तर एक सापेक्ष पथ हो सकता है: जो कुछ भी सिमलिंक तर्क का मूल्य था।
तथापि, readlink
विकल्प (-f -e or -m) है जो सभी फाइलों के लिए काम करेगा, और तर्क द्वारा निरूपित फ़ाइल को एक पूर्ण पथनाम (बिना किसी सहानुभूति के साथ) देगा।
यह किसी भी चीज़ के लिए ठीक काम करता है, जो सिम्लिंक नहीं है, हालांकि कोई भी पथ पर मध्यवर्ती सीमलिंक को हल किए बिना एक पूर्ण पथनाम का उपयोग करने की इच्छा कर सकता है। यह कमांड द्वारा किया जाता हैrealpath -s foo
एक सहानुभूति तर्क के मामले में, readlink
इसके विकल्प के साथ फिर से तर्क के लिए निरपेक्ष पथ पर सभी सिमिलिंक को हल किया जाएगा, लेकिन इसमें वे सभी सिमिलिंक भी शामिल होंगे जिनका तर्क मान का अनुसरण करके सामना किया जा सकता है। आप यह नहीं चाह सकते हैं कि यदि आप तर्क से सहानुभूति के लिए एक पूर्ण मार्ग चाहते हैं, बजाय इसके कि वह जो भी लिंक कर सकता है। फिर से, यदि foo
एक सिमलिंक है , तो सहानुभूति realpath -s foo
को हल किए बिना एक पूर्ण मार्ग प्राप्त होगा, जिसमें तर्क के रूप में दिया गया है।
-s
विकल्प के बिना , realpath
बहुत कुछ वैसा ही करता है readlink
, जैसे
किसी लिंक के मूल्य को पढ़ने के साथ-साथ कई अन्य चीजों को छोड़कर। यह मेरे लिए स्पष्ट नहीं है कि readlink
इसके विकल्प क्यों हैं, जिससे स्पष्ट रूप से एक अवांछनीय अतिरेक पैदा होता है
realpath
।
वेब को एक्सप्लोर करना बहुत अधिक नहीं कहता है, सिवाय इसके कि पूरे सिस्टम में कुछ बदलाव हो सकते हैं।
निष्कर्ष: realpath
सबसे लचीलेपन के साथ उपयोग करने के लिए सबसे अच्छा आदेश है, कम से कम यहां अनुरोधित उपयोग के लिए।
मेरा पसंदीदा समाधान एक था @EugenKonkov द्वारा क्योंकि यह अन्य उपयोगिताओं (कोरुटिल्स पैकेज) की उपस्थिति का मतलब नहीं था।
लेकिन यह रिश्तेदार रास्तों के लिए विफल रहा "।" और "..", इसलिए यहां इन विशेष मामलों को संभालने वाला थोड़ा बेहतर संस्करण है।
यह अभी भी विफल रहता है यदि उपयोगकर्ता के पास cd
संबंधित पथ के मूल निर्देशिका में अनुमति नहीं है , हालांकि।
#! /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
}
यूजेन का जवाब मेरे लिए काफी काम का नहीं था, लेकिन यह किया:
absolute="$(cd $(dirname \"$file\"); pwd)/$(basename \"$file\")"
साइड नोट, आपकी वर्तमान कार्यशील निर्देशिका अप्रभावित है।
सबसे अच्छा समाधान, imho, यहाँ पोस्ट किया गया एक है: https://stackoverflow.com/a/3373298/9724628 ।
इसे काम करने के लिए अजगर की आवश्यकता होती है, लेकिन यह सभी या अधिकांश किनारे मामलों को कवर करने और बहुत ही पोर्टेबल समाधान होने लगता है।
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
आप मैक ओएस एक्स पर बैश जो न तो है उपयोग कर रहे हैं realpath ही अस्तित्व में है और न ही इसकी readlink निरपेक्ष पथ मुद्रित कर सकते हैं, तो आप चारा नहीं कोड के लिए अपने स्वयं के संस्करण इसे प्रिंट करना पड़ सकता है। यहाँ मेरा कार्यान्वयन है:
(शुद्ध बैश)
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[*]}"
)
}
(उपयोग gawk)
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)
#!/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)
}
उदाहरण:
$ abspath I/am/.//..//the/./god/../of///.././war
/Users/leon/I/the/war
यदि सापेक्ष पथ एक निर्देशिका पथ है, तो मेरा प्रयास करें, सबसे अच्छा होना चाहिए:
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") } }'
@ Ernest-a के बजाय एक अच्छा संस्करण में सुधार:
absolute_path() {
cd "$(dirname "$1")"
case $(basename $1) in
..) echo "$(dirname $(pwd))";;
.) echo "$(pwd)";;
*) echo "$(pwd)/$(basename $1)";;
esac
}
यह उस मामले से सही तरीके से निपटता है जहां पथ का अंतिम तत्व है ..
, जिस स्थिति "$(pwd)/$(basename "$1")"
में @ ernest-a का उत्तर इस प्रकार से आएगा accurate_sub_path/spurious_subdirectory/..
।
यदि आप किसी परिवर्तनशील पथ वाले चर को पूर्ण रूप में बदलना चाहते हैं, तो यह काम करता है:
dir=`cd "$dir"`
"cd" कार्य निर्देशिका को बदले बिना गूँजता है, क्योंकि यहाँ एक उप-शेल में निष्पादित किया गया है।
dir=`cd ".."` && echo $dir
यह अन्य सभी से एक जंजीर समाधान है, उदाहरण के लिए, जब realpath
विफल रहता है, या तो क्योंकि यह स्थापित नहीं है या क्योंकि यह त्रुटि कोड के साथ बाहर निकलता है, तब, अगले समाधान का प्रयास किया जाता है जब तक कि यह मार्ग सही न हो जाए।
#!/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")" "${?}"
आप किसी भी रिश्तेदार पथ $ लाइन के लिए बैश स्ट्रिंग प्रतिस्थापन का उपयोग कर सकते हैं:
line=$(echo ${line/#..\//`cd ..; pwd`\/})
line=$(echo ${line/#.\//`pwd`\/})
echo $line
मूल मोर्चे का स्ट्रिंग प्रतिस्थापन
$ {string / # substring / प्रतिस्थापन} के सूत्र का अनुसरण करता है
जिसकी चर्चा यहाँ अच्छी तरह से की गई है: https://www.tldp.org/LDP/abs/html/string-manipulation.html
\
चरित्र को नकारता /
है जब हम यह स्ट्रिंग है कि हम पाते हैं / की जगह का हिस्सा बनना चाहते हैं।
मैं मैक ओएस कैटालिना, उबंटू 16 और सेंटोस 7 के बीच बड़े करीने से एक समाधान खोजने में असमर्थ था, इसलिए मैंने इसे अजगर इनलाइन के साथ करने का फैसला किया और इसने मेरी बैश स्क्रिप्ट के लिए अच्छा काम किया।
to_abs_path() {
python -c "import os; print os.path.abspath('$1')"
}
to_abs_path "/some_path/../secrets"