बैश में एक संभावित रिश्तेदार पथ का विस्तार करें


82

मेरी स्क्रिप्ट के तर्क के रूप में कुछ फ़ाइल पथ हैं। वे निश्चित रूप से, रिश्तेदार हो सकते हैं (या ~ ~ होते हैं)। लेकिन मेरे द्वारा लिखे गए कार्यों के लिए मुझे ऐसे रास्तों की आवश्यकता होती है जो निरपेक्ष हों, लेकिन उनके सिमिलिंक हल नहीं होते हैं।

क्या इसका कोई कार्य है?


1
रीडलिंक फ़ंक्शन आज़माएँ - andy.wordpress.com/2008/05/09/bash-equivalent-for-php-realpath
arunkumar

7
readlinkसहानुभूति का समाधान करता है; ओपी ऐसा नहीं चाहता है।
कीथ थॉम्पसन



1
echo $(cd some_directory && pwd), अगर कोई_निगम मौजूद नहीं है, तो सिम्लिंक को हल न करें। कार्यशील निर्देशिका प्रभावित नहीं हुई। या एक चर के लिए असाइन करें MY_PATH=$(cd some_directory && pwd)
क्यूटीज़ी

जवाबों:


79

MY_PATH=$(readlink -f $YOUR_ARG)की तरह संबंधित पथ का समाधान हो जाएगा "./"और"../"

इस पर भी विचार करें ( स्रोत ):

#!/bin/bash
dir_resolve()
{
cd "$1" 2>/dev/null || return $?  # cd to desired directory; if fail, quell any error messages but return exit status
echo "`pwd -P`" # output full, link-resolved path
}

# sample usage
if abs_path="`dir_resolve \"$1\"`"
then
echo "$1 resolves to $abs_path"
echo pwd: `pwd` # function forks subshell, so working directory outside function is not affected
else
echo "Could not reach $1"
fi

यह निश्चित रूप से अच्छा है, लेकिन समस्या यह है कि simlinks हल कर रहे हैं, और जो उपयोगकर्ताओं के साथ कुछ भ्रम पैदा करेगा।
लॉर

man pwd: "- भौतिक वर्तमान कार्य निर्देशिका (सभी प्रतीकात्मक लिंक को हल किया गया) को प्रदर्शित करें",-P
andens

7
readlink -fOS X पर कार्यक्षमता प्राप्त करने के लिए , आप Homebrew का उपयोग कर सकते हैं और फिर चला $ brew install coreutils सकते हैं : फिर आप उपयोग कर सकते हैं greadlink -f
jgpawletko

46

http://www.linuxquestions.org/questions/programming-9/bash-script-return-full-path-and-filename-680368/page3.html निम्नलिखित है

function abspath {
    if [[ -d "$1" ]]
    then
        pushd "$1" >/dev/null
        pwd
        popd >/dev/null
    elif [[ -e "$1" ]]
    then
        pushd "$(dirname "$1")" >/dev/null
        echo "$(pwd)/$(basename "$1")"
        popd >/dev/null
    else
        echo "$1" does not exist! >&2
        return 127
    fi
}

जो उपयोग करता है pushd/ popdएक राज्य में जाने के लिए जहां pwdउपयोगी है।


2
अफसोस की बात है, यह वास्तव में यहाँ पर सबसे अच्छा जवाब है और यह वोट नहीं है कि यह कहाँ से है। ओपी के सवाल का सही जवाब देने के लिए +1। वह चाहता है कि सहानुभूति का समाधान न हो, जो वास्तव में बैश के स्थानीय होने का सवाल है DIRSTACKऔर कुछ नहीं। अच्छा समाधान!
cptstubing06

5
जब मानक shअनुकूलता के लिए लक्ष्य किया जाता है , तो pushd; cd <dir>; <cmd>; popdइसे प्रतिस्थापित किया जा सकता है (cd <dir>; <cmd>)
अबाफेई

16

सरल एक-लाइनर:

function abs_path {
  (cd "$(dirname '$1')" &>/dev/null && printf "%s/%s" "$PWD" "${1##*/}")
}

उपयोग:

function do_something {
    local file=$(abs_path $1)
    printf "Absolute path to %s: %s\n" "$1" "$file"
}
do_something $HOME/path/to/some\ where

मैं अभी भी यह पता लगाने की कोशिश कर रहा हूं कि मैं कैसे पूरी तरह से इस बात से बेखबर हो सकता हूं कि रास्ता मौजूद है या नहीं (इसलिए इसका इस्तेमाल फाइल बनाते समय भी किया जा सकता है)।


1
क्या यह वर्तमान कार्यशील निर्देशिका को नहीं बदलेगा? क्या मुझे cd -बाद में इसे रीसेट करना चाहिए ?
devios1

4
कोई जरुरत नहीं है। Parens पर ध्यान दें, वे अंदर के आदेशों को एक उपधारा में चलाने का कारण बनते हैं। उपधारा की राज्य (जैसे कार्यशील निर्देशिका) अपने मूल शेल में लीक नहीं होती है। यहाँ और पढ़ें: tldp.org/LDP/abs/html/subshells.html
andsens

1
अच्छा एक लाइनर। एक समस्या है, हालांकि: यदि $ 1 के विस्तारित मूल्य में कोई स्लैश नहीं है (अर्थात यह वर्तमान निर्देशिका में एक फ़ाइल नाम है), तो $ {1% / *} फ़ाइल नाम के लिए ही फैलता है और सीडी कमांड विफल रहता है। आप इसके बजाय $ (dirname $ 1) का उपयोग करना चाह सकते हैं, जो 'का विस्तार करेगा।' उस स्तिथि में।
पाउलो

आप सही हैं, अपडेटेड हैं। मैं जगह के साथ कुछ के हवाले से समस्या है ${1##*/}के साथ basenameहै, हालांकि एक अलग चर में डालने के बिना, रिक्तियों के साथ पथ ठीक से काम नहीं करते।
सेंस

1
@BryanP मैं वास्तव में dotfile सिंक्रोनाइज़र के लिए पूरी तरह से खत्म हो गया है जिसे मैं बनाए रख रहा हूं। इसमें एक क्लीन_पैथ () फ़ंक्शन है जो अनावश्यक पथ भागों को हटाता है, यदि आप इसके अंत में एक रिश्तेदार पथ को $PWD
चिपकाते हैं

8

यह ओएस एक्स पर मेरे लिए चाल करता है: $(cd SOME_DIRECTORY 2> /dev/null && pwd -P)

यह कहीं भी काम करना चाहिए। अन्य समाधान बहुत जटिल लग रहे थे।


4

OS X पर आप उपयोग कर सकते हैं

stat -f "%N" YOUR_PATH

लिनक्स पर आप realpathनिष्पादन योग्य हो सकते हैं । यदि नहीं, तो निम्नलिखित काम कर सकते हैं (न केवल लिंक के लिए):

readlink -c YOUR_PATH

20
ओएस एक्स जवाब काम नहीं करता है। stat -f "%N" PATHमुझे वही रास्ता देता है जो मैंने दिया था।
लिली बॉलर

3

का उपयोग करें readlink -f <relative-path>, जैसे

export FULLPATH=`readlink -f ./`

2

शायद यह अधिक पठनीय है और एक उपधारा का उपयोग नहीं करता है और वर्तमान dir नहीं बदलता है:

dir_resolve() {
  local dir=`dirname "$1"`
  local file=`basename "$1"`
  pushd "$dir" &>/dev/null || return $? # On error, return error code
  echo "`pwd -P`/$file" # output full, link-resolved path with filename
  popd &> /dev/null
}

1

एक और तरीका है। आप एक रिश्तेदार पथ को हल करने के लिए बैश स्क्रिप्ट में अजगर एम्बेडिंग का उपयोग कर सकते हैं।

abs_path=$(python3 - <<END
from pathlib import Path
path = str(Path("$1").expanduser().resolve())
print(path)
END
)

0

स्वयं संपादित करें, मैंने अभी देखा कि ओपी ने कहा कि वह सहानुभूति की तलाश नहीं कर रहा है:

"लेकिन मेरे द्वारा लिखे गए कार्यों के लिए मुझे उन रास्तों की आवश्यकता है जो निरपेक्ष हैं, लेकिन उनके सिम्बल को हल नहीं किया गया है।"

तो लगता है कि यह सब के बाद अपने सवाल के लिए इतना apropos नहीं है। :)

चूँकि मैंने वर्षों में कई बार इसमें भाग लिया है, और इस बार मेरे चारों ओर एक शुद्ध बैश पोर्टेबल संस्करण की आवश्यकता थी जिसे मैं OSX और लिनक्स पर उपयोग कर सकता था, मैंने आगे बढ़कर एक लिखा:

जीवित संस्करण यहां रहता है:

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

लेकिन एसओ के लिए, यहाँ वर्तमान संस्करण है (मुझे लगता है कि यह अच्छी तरह से परीक्षण किया गया है..लेकिन मैं प्रतिक्रिया के लिए खुला हूँ!)

यह सादे बोर्न शेल (श) के लिए काम करना मुश्किल नहीं हो सकता है, लेकिन मैंने कोशिश नहीं की ... मुझे $ FUNCNAME बहुत पसंद है। :)

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

यहाँ एक उत्कृष्ट उदाहरण है, काढ़ा करने के लिए धन्यवाद:

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

इस फ़ंक्शन का उपयोग करें और यह -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

यदि आपका OS इसका समर्थन करता है, तो उपयोग करें:

realpath "./some/dir"

और एक चर में इसका उपयोग करना:

some_path="$(realpath "./some/dir")"

जिससे आपके मार्ग का विस्तार होगा। उबंटू और CentOS पर परीक्षण किया गया, शायद आप पर उपलब्ध न हों। कुछ रीडिंक की सलाह देते हैं, लेकिन रीडलिंक के लिए प्रलेखन कहते हैं:

नोट realpath (1) canonicalization कार्यक्षमता के लिए उपयोग करने के लिए पसंदीदा कमांड है।

मामले में लोगों को आश्चर्य है कि मैं अपने चर को क्यों उद्धृत करता हूं, यह पथों में रिक्त स्थान को संरक्षित करने के लिए है। जैसे करने realpath some pathसे आपको दो अलग-अलग मार्ग परिणाम मिलेंगे। लेकिन realpath "some path"एक लौटेगा। उद्धृत पैरामीटर ftw :)


-1

क्या आपको विशेष रूप से बैश का उपयोग करना है? मुझे ऐसा करने की आवश्यकता थी और लिनक्स और ओएस एक्स के बीच अंतर से तंग आ गया। इसलिए मैंने एक त्वरित और गंदे समाधान के लिए PHP का उपयोग किया।

#!/usr/bin/php <-- or wherever
<?php
{
   if($argc!=2)
      exit();
   $fname=$argv[1];
   if(!file_exists($fname))
      exit();
   echo realpath($fname)."\n";
}
?>

मुझे पता है कि यह एक बहुत ही सुंदर समाधान नहीं है, लेकिन यह काम करता है।


यह फ़ाइल के लिए पथ के अलावा कुछ भी नहीं करता है यदि आप पहले से ही फ़ाइल का पथ जानते हैं या फ़ाइल वर्तमान dir में है ... फ़ाइल को पथ सेटिंग्स में नहीं मिलता है
G-Man
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.