मैं एक मैक पर जीएनयू के रीडलिंक का व्यवहार कैसे प्राप्त कर सकता हूं?


376

लिनक्स पर, readlinkउपयोगिता एक विकल्प को स्वीकार करती है जो -fअतिरिक्त लिंक का अनुसरण करती है। यह मैक और संभवतः बीएसडी आधारित प्रणालियों पर काम नहीं करता है। समकक्ष क्या होगा?

यहाँ कुछ डिबग जानकारी है:

$ which readlink; readlink -f
/usr/bin/readlink
readlink: illegal option -f
usage: readlink [-n] [file ...]

1
थोड़ा देर से, लेकिन आपके प्रश्न में आपके द्वारा उपयोग किए गए शेल का कोई उल्लेख नहीं है। यह प्रासंगिक है, क्योंकि readlinkएक अंतर्निहित या बाहरी कमांड हो सकता है।
0xC0000022L

1
शायद यही अंतर समझाएगा। मुझे पूरा यकीन है कि मैंने दोनों अवसरों पर बैश का इस्तेमाल किया था।
troelskn

1
मैक पर यह विकल्प अवैध क्यों है?
कॉममाटोस्ट

3
मैं वास्तव में कामना करता हूं कि Apple OS X को अधिक डिफॉल्ट लिनक्स पथों का समर्थन करेगा, और इस तरह की चीजों को संबोधित करेगा। वे कुछ भी किए बिना कर सकते थे, वे नहीं कर सकते थे?
कॉममाटॉस्ट

1
@CommaToast ठीक है, वे पर्ल के साथ जहाज करते हैं +++ ... टर्मिनल खोलें और टाइप करें: touch myfile ; ln -s myfile otherfile ; perl -MCwd=abs_path -le 'print abs_path readlink(shift);' otherfile... मेरे मामले में मैं देख रहा हूं: / उपयोगकर्ता / cito / myfile`। नीचे मेरी प्रतिक्रिया में इसे जोड़ा गया। चीयर्स।
जी। Cito

जवाबों:


181

readlink -f दो काम करता है:

  1. यह सहानुभूति के एक क्रम के साथ पुनरावृत्ति करता है जब तक कि यह एक वास्तविक फ़ाइल नहीं पाता।
  2. यह उस फ़ाइल के कैनोनिकलाइज़्ड नाम को लौटाता है - अर्थात, इसका पूर्ण पथनाम।

यदि आप चाहते हैं, तो आप केवल एक शेल स्क्रिप्ट का निर्माण कर सकते हैं जो समान चीज़ को प्राप्त करने के लिए वेनिला रीडलिंक व्यवहार का उपयोग करता है। यहाँ एक उदाहरण है। जाहिर है आप इसे अपनी स्क्रिप्ट में सम्मिलित कर सकते हैं जहाँ आप कॉल करना चाहते हैंreadlink -f

#!/bin/sh

TARGET_FILE=$1

cd `dirname $TARGET_FILE`
TARGET_FILE=`basename $TARGET_FILE`

# Iterate down a (possible) chain of symlinks
while [ -L "$TARGET_FILE" ]
do
    TARGET_FILE=`readlink $TARGET_FILE`
    cd `dirname $TARGET_FILE`
    TARGET_FILE=`basename $TARGET_FILE`
done

# Compute the canonicalized name by finding the physical path 
# for the directory we're in and appending the target file.
PHYS_DIR=`pwd -P`
RESULT=$PHYS_DIR/$TARGET_FILE
echo $RESULT

ध्यान दें कि इसमें कोई त्रुटि हैंडलिंग शामिल नहीं है। विशेष महत्व के, यह सिमलिंक चक्रों का पता नहीं लगाता है। ऐसा करने का एक सरल तरीका यह होगा कि आप लूप के चारों ओर जाने वाले समय की संख्या की गणना करें और यदि आप एक बड़ी संख्या में, जैसे कि 1,000 को हिट करते हैं तो असफल हो जाते हैं।

के pwd -Pबजाय का उपयोग करने के लिए आदर्श $PWD

ध्यान दें कि यह लिपि यह पसंद करती है कि आप GNU रीडलिंक की तरह उपयोग करने में सक्षम होना चाहते हैं , तो इसे बदल दें ./script_name filename, नहीं ।-f$1$2-f filename


1
जहाँ तक मैं बता सकता हूँ, यह काम नहीं करेगा अगर पथ के एक माता पिता को एक सिमिलिंक है। उदाहरण के लिए। यदि foo -> /var/cux, तो foo/barहल नहीं किया जाएगा, क्योंकि barएक लिंक नहीं है, हालांकि fooहै।
troelskn

1
आह। हाँ। यह उतना सरल नहीं है लेकिन इससे निपटने के लिए आप उपरोक्त स्क्रिप्ट को अपडेट कर सकते हैं। मैं तदनुसार उत्तर (पुन: लिखूंगा, वास्तव में) संपादित करूंगा।
कीथ स्मिथ

खैर, एक लिंक पथ में कहीं भी हो सकता है। मुझे लगता है कि स्क्रिप्ट पथ के प्रत्येक भाग पर पुनरावृति कर सकती है, लेकिन यह तब थोड़ा जटिल हो जाता है।
troelskn

1
धन्यवाद। समस्या यह है कि $ पीडब्ल्यूडी हमें तार्किक कार्य निर्देशिका दे रहा है, जो हमने अनुसरण किए गए सिमिलिंक में मूल्यों के आधार पर किया है। हम वास्तविक भौतिक निर्देशिका को 'pwd -P' के साथ प्राप्त कर सकते हैं। इसे फाइल सिस्टम की जड़ तक ".." का पीछा करते हुए गणना करनी चाहिए। मैं अपने जवाब के अनुसार स्क्रिप्ट को अपडेट करूंगा।
कीथ स्मिथ

12
महान समाधान, लेकिन यह उन रास्तों से ठीक से नहीं निपटता है जिनमें भागने की आवश्यकता होती है , जैसे कि फ़ाइल या निर्देशिका नाम एम्बेडेड रिक्त स्थान के साथ । उपाय करने कि, उपयोग cd "$(dirname "$TARGET_FILE")" और TARGET_FILE=$(readlink "$TARGET_FILE")और TARGET_FILE=$(basename "$TARGET_FILE")इसके बाद के संस्करण कोड में उपयुक्त स्थानों में।
22

438

MacPorts और Homebrew एक प्रदान coreutils पैकेज युक्त greadlink(जीएनयू readlink)। Mackb.com में माइकल कल्लवीट पोस्ट को श्रेय।

brew install coreutils

greadlink -f file.txt

यदि आप बैश के अलावा अन्य स्थानों से रीडिंक कॉल कर रहे हैं, तो एक और समाधान निकाल दिया जाएगा / usr / bin / readlink तो / usr / स्थानीय / बिन / greadlink के लिए एक लिंक बनाएं।
चिंगलुन

8
कृपया न करें, जब तक कि आप) अपने स्वयं के ख के लिए सॉफ्टवेयर न लिखें) दूसरों के साथ गड़बड़ करना चाहते हैं। इसे इस तरह से लिखें कि यह किसी के लिए "बस काम करता है"।
किलोडे

14
@ खुजली इसके बजाय अपने में करें .bashrc:export PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"
bfontaine

1
सवाल ओएस एक्स या बीएसडी सिस्टम पर समकक्ष के लिए पूछता है, इसका जवाब नहीं है। आपको Homebrew भी इंस्टॉल करना होगा। आप GNU रीडलिंक के अलावा भी कई चीजें स्थापित करेंगे। यदि आप मानक OS X के लिए स्क्रिप्ट लिख रहे हैं, तो यह उत्तर मदद नहीं करेगा। आप कुछ भी स्थापित किए बिना, ओएस एक्स pwd -Pऔर readlinkऑन के संयोजन का उपयोग कर सकते हैं
जेसन एस

4
मैं अपने मैक पर जीएनयू और अन्य बर्तन चाहता था कि मेरा मानना ​​है कि उपसर्ग के बिना, और अपने उपयोगकर्ता से आसानी से सुलभ है PATH। ऊपर से शुरू किया था brew install <package> --default-names। कई बार इस साइट पर एक प्रश्न का उत्तर थोड़ा, या अधिक, पूछने वाले की तकनीकी आवश्यकताओं के बाहर, लेकिन इसी तरह की स्थिति के भीतर दिया गया है, और अभी भी बहुत उपयोगी है। topbug.net/blog/2013/04/14/…
पिसिस

43

आप में रुचि हो सकती है realpath(3)या पायथन है os.path.realpath। दोनों बिल्कुल समान नहीं हैं; सी लाइब्रेरी कॉल के लिए आवश्यक है कि मध्यस्थ पथ घटक मौजूद हैं, जबकि पायथन संस्करण नहीं है।

$ pwd
/tmp/foo
$ ls -l
total 16
-rw-r--r--  1 miles    wheel  0 Jul 11 21:08 a
lrwxr-xr-x  1 miles    wheel  1 Jul 11 20:49 b -> a
lrwxr-xr-x  1 miles    wheel  1 Jul 11 20:49 c -> b
$ python -c 'import os,sys;print(os.path.realpath(sys.argv[1]))' c
/private/tmp/foo/a

मुझे पता है कि आपने कहा था कि आप किसी अन्य स्क्रिप्टिंग भाषा की तुलना में कुछ अधिक हल्के होंगे, लेकिन बस एक द्विआधारी संकलित होने की स्थिति में आप लाइब्रेरी कॉल को लपेटने के लिए पायथन और सीटीपी (मैक ओएस एक्स 10.5 पर उपलब्ध) का उपयोग कर सकते हैं:

#!/usr/bin/python

import ctypes, sys

libc = ctypes.CDLL('libc.dylib')
libc.realpath.restype = ctypes.c_char_p
libc.__error.restype = ctypes.POINTER(ctypes.c_int)
libc.strerror.restype = ctypes.c_char_p

def realpath(path):
    buffer = ctypes.create_string_buffer(1024) # PATH_MAX
    if libc.realpath(path, buffer):
        return buffer.value
    else:
        errno = libc.__error().contents.value
        raise OSError(errno, "%s: %s" % (libc.strerror(errno), buffer.value))

if __name__ == '__main__':
    print realpath(sys.argv[1])

विडंबना यह है कि इस लिपि का C संस्करण छोटा होना चाहिए। :)


हां, realpathवास्तव में मैं जो चाहता हूं। लेकिन यह बहुत अजीब लगता है कि मुझे शेल फ़ंक्शन से इस फ़ंक्शन को प्राप्त करने के लिए एक बाइनरी संकलित करना होगा।
ट्रॉयल्सनो

4
फिर शेल स्क्रिप्ट में पायथन वन-लाइनर का उपयोग क्यों नहीं किया गया? (एक-लाइन कॉल से readlinkखुद को अलग करने के लिए ऐसा नहीं है, क्या यह है?)
टेलीमेकस

3
python -c "import os,sys; print(os.path.realpath(os.path.expanduser(sys.argv[1])))" "${1}"रास्तों के साथ काम करता है जैसे'~/.symlink'
वेस टर्नर

@troelskin मुझे एहसास नहीं था कि पर्ल, पायथन, आदि "अनुमति" थे !! ... उस मामले में मैं perl -MCwd=abs_path -le 'print abs_path readlink(shift);'अपने जवाब में जोड़ने जा रहा हूँ :-)
जी। Cito

27

मुझे अभी तक एक और कार्यान्वयन के साथ ढेर करने से नफरत है, लेकिन मुझे एक) पोर्टेबल, शुद्ध शेल कार्यान्वयन , और बी) यूनिट-टेस्ट कवरेज की आवश्यकता थी , क्योंकि इस तरह के कुछ के लिए किनारे-मामलों की संख्या गैर-तुच्छ है

परीक्षण और पूर्ण कोड के लिए Github पर मेरी परियोजना देखें । कार्यान्वयन का एक सारांश क्या है:

जैसा कि कीथ स्मिथ ने सूक्ष्म रूप से बताया है, readlink -fदो चीजें करता है: 1) पुनरावृत्ति के साथ सहानुभूति का समाधान करता है, और 2) परिणाम को रद्द करता है, इसलिए:

realpath() {
    canonicalize_path "$(resolve_symlinks "$1")"
}

सबसे पहले, सिमलिंक रिज़ॉल्वर कार्यान्वयन:

resolve_symlinks() {
    local dir_context path
    path=$(readlink -- "$1")
    if [ $? -eq 0 ]; then
        dir_context=$(dirname -- "$1")
        resolve_symlinks "$(_prepend_path_if_relative "$dir_context" "$path")"
    else
        printf '%s\n' "$1"
    fi
}

_prepend_path_if_relative() {
    case "$2" in
        /* ) printf '%s\n' "$2" ;;
         * ) printf '%s\n' "$1/$2" ;;
    esac 
}

ध्यान दें कि यह पूर्ण कार्यान्वयन का थोड़ा सरलीकृत संस्करण है । पूर्ण क्रियान्वयन से सिमलिंक चक्रों के लिए एक छोटा सा चेक जोड़ा जाता है , साथ ही साथ आउटपुट को थोड़ा मालिश करता है।

अंत में, एक मार्ग को स्पष्ट करने के लिए कार्य:

canonicalize_path() {
    if [ -d "$1" ]; then
        _canonicalize_dir_path "$1"
    else
        _canonicalize_file_path "$1"
    fi
}   

_canonicalize_dir_path() {
    (cd "$1" 2>/dev/null && pwd -P) 
}           

_canonicalize_file_path() {
    local dir file
    dir=$(dirname -- "$1")
    file=$(basename -- "$1")
    (cd "$dir" 2>/dev/null && printf '%s/%s\n' "$(pwd -P)" "$file")
}

कमोबेश यही है। अपनी स्क्रिप्ट में पेस्ट करने के लिए पर्याप्त सरल है, लेकिन इतना मुश्किल है कि आप किसी भी कोड पर भरोसा करने के लिए पागल होंगे जो आपके उपयोग के मामलों के लिए यूनिट परीक्षण नहीं करता है।


3
यह POSIX नहीं है - यह गैर-POSIX localकीवर्ड का उपयोग करता है
go2null

यह न के बराबर है readlink -f, न ही realpath। स्थापित किए गए कोर्यूटिल्स फॉर्मूले के साथ एक मैक मान लें (इसलिए greadlinkउपलब्ध के साथ ), इसके साथ प्रयास करें ln -s /tmp/linkeddir ~/Documents; greadlink -f /tmp/linkeddir/..आपकी होम निर्देशिका (यह हल प्रिंट /tmp/linkeddirलागू करने से पहले लिंक ..माता पिता dir रेफरी), लेकिन अपने कोड का उत्पादन /private/tmp/के रूप में /tmp/linkeddir/..एक सिमलिंक नहीं है, लेकिन -d /tmp/linkeddir/..सच है और इतने cd /tmp/linkeddir/..पर ले जाता है /tmp, जिसका विहित मार्ग है /private/tmp। आपका कोड realpath -Lइसके बजाय, क्या करता है।
मार्टिन पीटर्स

27

पर्ल में एक साधारण एक-लाइनर जो किसी भी बाहरी निर्भरता के बिना लगभग हर जगह काम करना सुनिश्चित करता है:

perl -MCwd -e 'print Cwd::abs_path shift' ~/non-absolute/file

सहानुभूति को कम करेगा।

एक स्क्रिप्ट में उपयोग इस तरह हो सकता है:

readlinkf(){ perl -MCwd -e 'print Cwd::abs_path shift' "$1";}
ABSPATH="$(readlinkf ./non-absolute/file)"

4
एक अनुगामी न्यूलाइन पाने के लिए -l, जैसेperl -MCwd -le 'print Cwd::abs_path shift' ~/non-absolute/file
pjvandehaar

26
  1. होमब्रे स्थापित करें
  2. भागो "काढ़ा स्थापित करें"
  3. "Greadlink -f पाथ" चलाएँ

greadlink gnu readlink है, जो लागू करता है -f। आप मैक्रोपोर्ट या अन्य का भी उपयोग कर सकते हैं, मुझे होमब्रे पसंद है।


2
मैं 2010 में दिए गए उत्तर stackoverflow.com/a/4031502/695671 पर
जेसन एस

यदि आपको इन आदेशों को उनके सामान्य नामों के साथ उपयोग करने की आवश्यकता है, तो आप अपने bashrc से अपने PATH में "gnubin" निर्देशिका जोड़ सकते हैं जैसे: PATH = "/ usr / local / opt / coreutils / libexec / gnubin: $ PATH"
डेनिस

20

मैंने वास्तविक रूप से वास्तविकपथ नामक एक स्क्रिप्ट बनाई है जो कुछ इस तरह दिखाई देती है:

#!/usr/bin/env python
import os.sys
print os.path.realpath(sys.argv[1])

आपको यह बदलना चाहिए कि sys.argv[1]यदि आप चाहते हैं कि स्क्रिप्ट पहले तर्क के रियलपैथ को प्रिंट करे। sys.argv[0]सिर्फ पाइटोन लिपि के वास्तविक मार्ग को ही प्रिंट करता है, जो बहुत उपयोगी नहीं है।
जैकब एगर

17
यहाँ का उपनाम संस्करण है, इसके लिए ~/.profile:alias realpath="python -c 'import os, sys; print os.path.realpath(sys.argv[1])'"
jwhitlock

शानदार जवाब, और महान वन-लाइनर @jwhitlock। चूंकि ओपी ने उद्धृत किया था readlink -f, यहाँ संभव -fध्वज का समर्थन करने के लिए @jwhitlock के उपनाम का एक संशोधित संस्करण है : alias realpath="python -c 'import os, sys; print os.path.realpath(sys.argv[2] if sys.argv[1] == \"-f\" else sys.argv[1])'"
कोडननिफर

11

इस बारे में क्या?

function readlink() {
  DIR="${1%/*}"
  (cd "$DIR" && echo "$(pwd -P)")
}

यह एकमात्र समाधान है जो मेरे लिए काम करता है; मुझे रास्तों को पार्स करने की जरूरत है जैसे ../../../->/
केफ्लाविच

अगर आपके पास सिस्टम के लिए पसंद किए जाने वाले /usr/bin/उदाहरण के लिए सिम्लिंक है तो यह काम नहीं कर सकता alternativesहै।
akostadinov

व्यक्तिगत फ़ाइलों के लिए काम नहीं करता है, केवल निर्देशिका। जीएनयू रीडिंक निर्देशिका, फाइल,
सिमलिंक

7

यहां एक पोर्टेबल शेल फ़ंक्शन है जो किसी भी बॉर्न तुलनीय शेल में काम करना चाहिए । यह सापेक्ष पथ विचलन को हल करेगा ".. या।" और प्रतीकात्मक प्रतीकात्मक लिंक।

यदि किसी कारणवश आपके पास एक realpath (1) कमांड नहीं है, या रीडलिंक (1) यह अलियास किया जा सकता है।

which realpath || alias realpath='real_path'

का आनंद लें:

real_path () {
  OIFS=$IFS
  IFS='/'
  for I in $1
  do
    # Resolve relative path punctuation.
    if [ "$I" = "." ] || [ -z "$I" ]
      then continue
    elif [ "$I" = ".." ]
      then FOO="${FOO%%/${FOO##*/}}"
           continue
      else FOO="${FOO}/${I}"
    fi

    ## Resolve symbolic links
    if [ -h "$FOO" ]
    then
    IFS=$OIFS
    set `ls -l "$FOO"`
    while shift ;
    do
      if [ "$1" = "->" ]
        then FOO=$2
             shift $#
             break
      fi
    done
    IFS='/'
    fi
  done
  IFS=$OIFS
  echo "$FOO"
}

यहां तक ​​कि अगर किसी को यहां दिलचस्पी है, तो 100% शुद्ध शेल कोड में बेसनेम और डिरनेम कैसे लागू किया जाए:

## http://www.opengroup.org/onlinepubs/000095399/functions/dirname.html
# the dir name excludes the least portion behind the last slash.
dir_name () {
  echo "${1%/*}"
}

## http://www.opengroup.org/onlinepubs/000095399/functions/basename.html
# the base name excludes the greatest portion in front of the last slash.
base_name () {
  echo "${1##*/}"
}

आप इस शेल कोड का अद्यतन संस्करण मेरी Google साइट पर देख सकते हैं: http://sites.google.com/site/jdisnard/realpath

EDIT: यह कोड 2-क्लॉज (फ्रीबीएसडी स्टाइल) लाइसेंस की शर्तों के तहत लाइसेंस प्राप्त है। मेरी साइट के लिए हाइपरलिंक का पालन करके लाइसेंस की एक प्रति मिल सकती है।


असली_पैथ बैश शेल में मैक ओएस एक्स शेर पर / पथ / के बजाय / फ़ाइल नाम के लिए रिटर्न / फ़ाइल नाम।

@ बैरी OSX स्नो लेपर्ड पर भी ऐसा ही होता है। इससे भी बदतर, real_path () संक्षिप्त आउटपुट के लिए लगातार कॉल!
डोमिनिक

@Dominique: आश्चर्य की बात नहीं है, क्योंकि फ़ंक्शन के अंदर अपने स्वयं के उप-भाग में नहीं चलाया जाता है ... वास्तव में बदसूरत और नाजुक।
0xC0000022L

7

FreeBSD और OSX का statNetBSD से व्युत्पन्न संस्करण है ।

आप प्रारूप स्विच के साथ आउटपुट को समायोजित कर सकते हैं (ऊपर दिए गए लिंक पर मैनुअल पेज देखें)।

%  cd  /service
%  ls -tal 
drwxr-xr-x 22 root wheel 27 Aug 25 10:41 ..
drwx------  3 root wheel  8 Jun 30 13:59 .s6-svscan
drwxr-xr-x  3 root wheel  5 Jun 30 13:34 .
lrwxr-xr-x  1 root wheel 30 Dec 13 2013 clockspeed-adjust -> /var/service/clockspeed-adjust
lrwxr-xr-x  1 root wheel 29 Dec 13 2013 clockspeed-speed -> /var/service/clockspeed-speed
% stat -f%R  clockspeed-adjust
/var/service/clockspeed-adjust
% stat -f%Y  clockspeed-adjust
/var/service/clockspeed-adjust

कुछ OS X संस्करणों में प्रारूपों के लिए विकल्प की stat कमी हो सकती -f%Rहै। इस मामले में -stat -f%Yपर्याप्त हो सकता है। -f%Yविकल्प के लिए एक सिमलिंक का लक्ष्य है, जबकि दिखाएगा -f%Rशो पूर्ण पथ नाम फ़ाइल के लिए इसी।

संपादित करें:

यदि आप पर्ल (डार्विन / ओएस एक्स का उपयोग हाल ही के कयासों के साथ करते हैं) करने में सक्षम हैं perl:

perl -MCwd=abs_path -le 'print abs_path readlink(shift);' linkedfile.txt

काम करेगा।


2
यह FreeBSD 10 पर सच है, लेकिन OS X 10.9 पर नहीं।
ज़ेन्ची

अच्छी पकड़। स्टेट मैनुअल पृष्ठ उद्धृत ओएस / एक्स 10.9 के लिए है। गायब होने का Rविकल्प -f%है। संभवतः stat -f%Yवांछित आउटपुट देता है। मैं उत्तर समायोजित करूंगा। ध्यान दें कि statटूल FreeBSD में संस्करण 4.10 में और NetBSD संस्करण 1.6 में दिखाई दिया।
जी। साइटो

10.15 पर पर्ल कमांड सही तरीके से काम नहीं करता है। इसे वर्तमान निर्देशिका में एक फ़ाइल दें और यह वर्तमान निर्देशिका (फ़ाइल के बिना) देता है।
कोडनिफ़र

7

इस समस्या को हल करने और मैक w / होमब्रे पर स्थापित या फ्रीबीएसडी पर रीडिंक की कार्यक्षमता को सक्षम करने का सबसे आसान तरीका 'कोरुटिल्स' पैकेज स्थापित करना है। कुछ लिनक्स वितरण और अन्य POSIX OS पर भी आवश्यक हो सकता है।

उदाहरण के लिए, FreeBSD 11 में, मैंने इनवाइट करके इंस्टॉल किया:

# pkg install coreutils

HomeOSw के साथ MacOS पर, कमांड होगी:

$ brew install coreutils

वास्तव में निश्चित नहीं है कि अन्य उत्तर इतने जटिल क्यों हैं, बस इतना ही है। फाइलें एक अलग स्थान पर नहीं हैं, वे अभी तक स्थापित नहीं हैं।


7
brew install coreutils --with-default-namesअधिक विशिष्ट होना। या आप इसके बजाय "greadlink" को समाप्त करेंगे ...
Henk

मैं 2010 stackoverflow.com/a/4031502/695671 से उत्तर के लिए कोई अंतर नहीं देख सकता और 2012 stackoverflow.com/a/9918368/695671 । प्रश्न वास्तव में है "... मैक और संभवतः बीएसडी आधारित प्रणालियों पर। क्या। बराबर हो? मैं नहीं मानता कि यह उस प्रश्न का बहुत अच्छा उत्तर है। कई कारण, लेकिन आप कुछ भी स्थापित करने की क्षमता के बिना मैक ओएस मशीनों को लक्षित कर सकते हैं। pwd -Pबहुत सरल है, लेकिन यह कई अन्य उत्तरों के बीच गायब हो जाता है, जिनमें बार-बार शामिल हैं, इसलिए डाउनवोट।
जेसन एस

3

अपडेट शुरू करें

यह एक ऐसी लगातार समस्या है, जिसे हमने मुफ्त उपयोग (एमआईटी लाइसेंस) के लिए बैश 4 लाइब्रेरी को एक साथ रखा है, जिसे रियलपैथ-लिब कहा जाता है । यह डिफ़ॉल्ट रूप से रीडलिंक-एफ का अनुकरण करने के लिए डिज़ाइन किया गया है और इसमें (1) सत्यापित करने के लिए दो परीक्षण सूट शामिल हैं कि यह किसी दिए गए यूनिक्स सिस्टम के लिए काम करता है और (2) यदि इंस्टॉल किया गया है तो रीडलिंक के खिलाफ । इसके अतिरिक्त, इसका उपयोग गहन, टूटे हुए सिम्लिंक और वृत्ताकार संदर्भों की जांच, पहचान और उनकी सुरक्षा के लिए किया जा सकता है, इसलिए यह गहरी-नेस्टेड भौतिक या प्रतीकात्मक निर्देशिका और फ़ाइल समस्याओं के निदान के लिए एक उपयोगी उपकरण हो सकता है। इसे github.com या bitbucket.org पर पाया जा सकता है ।

अंत अद्यतन

एक और बहुत ही कॉम्पैक्ट और कुशल समाधान जो किसी चीज पर भरोसा नहीं करता है लेकिन बैश है:

function get_realpath() {

    [[ ! -f "$1" ]] && return 1 # failure : file does not exist.
    [[ -n "$no_symlinks" ]] && local pwdp='pwd -P' || local pwdp='pwd' # do symlinks.
    echo "$( cd "$( echo "${1%/*}" )" 2>/dev/null; $pwdp )"/"${1##*/}" # echo result.
    return 0 # success

}

इसमें एक वातावरण सेटिंग भी शामिल है जो no_symlinksभौतिक प्रणाली के लिए सीमलिंक को हल करने की क्षमता प्रदान करता है। जब तक no_symlinksकिसी चीज़ के लिए सेट किया जाता है, no_symlinks='on'तब तक भौतिक प्रणाली के लिए सहानुभूति का समाधान किया जाएगा। अन्यथा उन्हें लागू किया जाएगा (डिफ़ॉल्ट सेटिंग)।

यह किसी भी सिस्टम पर काम करना चाहिए जो बैश प्रदान करता है, और परीक्षण प्रयोजनों के लिए एक बैश संगत निकास कोड लौटाएगा।


3

पहले से ही बहुत सारे उत्तर हैं, लेकिन मेरे लिए किसी ने भी काम नहीं किया ... इसलिए अब मैं इसका उपयोग कर रहा हूं।

readlink_f() {
  local target="$1"
  [ -f "$target" ] || return 1 #no nofile

  while [ -L "$target" ]; do
    target="$(readlink "$target")" 
  done
  echo "$(cd "$(dirname "$target")"; pwd -P)/$target"
}

1
यह काम नहीं करता है अगर $targetयह एक रास्ता है, यह केवल काम करता है अगर यह एक फ़ाइल है।
मैक्सगॉस्ट

3

एक आलसी तरीका जो मेरे लिए काम करता है,

$ brew install coreutils
$ ln -s /usr/local/bin/greadlink /usr/local/bin/readlink
$ which readlink
/usr/local/bin/readlink
/usr/bin/readlink

1

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

फ़ंक्शन get_realpath () नीचे सरल है, बैश-केंद्रित है, और किसी भी निर्भरता की आवश्यकता नहीं है। मैं केवल बैश बिल्डिंग्स इको और सीडी का उपयोग करता हूं । यह काफी हद तक सुरक्षित भी है, क्योंकि हर चीज को रास्ते के प्रत्येक चरण में परीक्षण किया जाता है और यह त्रुटि की स्थिति देता है।

यदि आप सिम्लिंक का पालन नहीं करना चाहते हैं, तो स्क्रिप्ट के सामने स्थित सेट -२ डाल दें , लेकिन अन्यथा सीडी को डिफ़ॉल्ट रूप से सिम्लिंक्स को हल करना चाहिए। यह फ़ाइल तर्कों के साथ परीक्षण किया गया है जो {निरपेक्ष | रिश्तेदार | सिमलिंक | स्थानीय} और यह फ़ाइल में पूर्ण पथ देता है। अभी तक हमें इससे कोई समस्या नहीं है।

function get_realpath() {

if [[ -f "$1" ]]
then
    # file *must* exist
    if cd "$(echo "${1%/*}")" &>/dev/null
    then
        # file *may* not be local
        # exception is ./file.ext
        # try 'cd .; cd -;' *works!*
        local tmppwd="$PWD"
        cd - &>/dev/null
    else
        # file *must* be local
        local tmppwd="$PWD"
    fi
else
    # file *cannot* exist
    return 1 # failure
fi

# reassemble realpath
echo "$tmppwd"/"${1##*/}"
return 0 # success

}

आप इसे अन्य कार्यों get_dirname, get_filename, get_stemname और validate_path के साथ जोड़ सकते हैं। ये हमारे GitHub रिपॉजिटरी में realpath-lib के रूप में पाया जा सकता है (पूर्ण प्रकटीकरण के - यह हमारा उत्पाद है लेकिन हम इसे बिना किसी प्रतिबंध के समुदाय को मुफ्त में प्रदान करते हैं)। यह एक अनुदेशात्मक उपकरण के रूप में भी काम कर सकता है - यह अच्छी तरह से प्रलेखित है।

हमने तथाकथित 'आधुनिक बैश' प्रथाओं को लागू करने के लिए अपनी पूरी कोशिश की है, लेकिन बैश एक बड़ा विषय है और मुझे यकीन है कि हमेशा सुधार के लिए जगह होगी। इसके लिए बैश 4+ की आवश्यकता होती है, लेकिन यदि वे अभी भी आसपास हैं तो पुराने संस्करणों के साथ काम करने के लिए बनाया जा सकता है।


1

चूंकि मेरे काम का उपयोग गैर-बीएसडी लिनक्स के साथ-साथ macOS के लोगों द्वारा किया जाता है, इसलिए मैंने अपनी निर्माण लिपियों में इन उपनामों का उपयोग करने का विकल्प चुना है ( sedक्योंकि इसमें समान मुद्दे हैं)

##
# If you're running macOS, use homebrew to install greadlink/gsed first:
#   brew install coreutils
#
# Example use:
#   # Gets the directory of the currently running script
#   dotfilesDir=$(dirname "$(globalReadlink -fm "$0")")
#   alias al='pico ${dotfilesDir}/aliases.local'
##

function globalReadlink () {
  # Use greadlink if on macOS; otherwise use normal readlink
  if [[ $OSTYPE == darwin* ]]; then
    greadlink "$@"
  else
    readlink "$@"
  fi
}

function globalSed () {
  # Use gsed if on macOS; otherwise use normal sed
  if [[ $OSTYPE == darwin* ]]; then
    gsed "$@"
  else
    sed "$@"
  fi
}

वैकल्पिक जांच आप अपने आप को homebrew + coreutils निर्भरता स्थापित करने के लिए जोड़ सकते हैं :

if [[ "$OSTYPE" == "darwin"* ]]; then
  # Install brew if needed
  if [ -z "$(which brew)" ]; then 
    /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"; 
  fi
  # Check for coreutils
  if [ -z "$(brew ls coreutils)" ]; then
    brew install coreutils
  fi
fi

मुझे लगता है कि वास्तव में "वैश्विक" होने के लिए इसे दूसरों की जांच करने की आवश्यकता है ... लेकिन यह शायद 80/20 के करीब आता है।


1

व्याख्या

कोरुटिल एक ऐसा brewपैकेज है जो जीएनयू / लिनक्स कोर उपयोगिताओं को स्थापित करता है जो उनके मैक ओएसएक्स कार्यान्वयन के अनुरूप हैं ताकि आप उन लोगों का उपयोग कर सकें

आप अपने मैक ओएसएक्स सिस्टम पर प्रोग्राम या उपयोगिता पा सकते हैं जो लिनक्स कोरुटिल्स ("कोर यूटिलिटीज") के समान प्रतीत होते हैं, फिर भी वे कुछ तरीकों से भिन्न होते हैं (जैसे अलग-अलग झंडे वाले)।

ऐसा इसलिए है क्योंकि इन उपकरणों के मैक OSX कार्यान्वयन अलग हैं। मूल GNU / लिनक्स-जैसा व्यवहार पाने के लिए आप पैकेज प्रबंधन प्रणाली के coreutilsमाध्यम से brewपैकेज को स्थापित कर सकते हैं ।

यह इसके द्वारा उपसर्ग किए गए संबंधित कोर उपयोगिताओं को स्थापित करेगा g। उदाहरण के लिए readlink, आपको एक संबंधित greadlinkप्रोग्राम मिलेगा ।

readlinkजीएनयू की तरह प्रदर्शन करने के लिए readlink(greadlink ) कार्यान्वयन की , आप कोरुटिल स्थापित करने के बाद एक साधारण उपनाम बना सकते हैं।

कार्यान्वयन

  1. काढ़ा स्थापित करें

Https://brew.sh/ पर दिए गए निर्देशों का पालन करें

  1. Coreutils पैकेज स्थापित करें

brew install coreutils

  1. एक उपनाम बनाएं

आप अपने उपनाम को ~ / .Bashrc, ~ / .bash_profile, या जहाँ भी आप अपने बैश उपनाम रखने के लिए उपयोग किया जाता है, में रख सकते हैं। मैं व्यक्तिगत रूप से मेरा ~ / .bashrc में रखता हूँ

alias readlink=greadlink

आप अन्य कोरटाइल जैसे gmv, gdu, gdf, और इसी तरह के लिए समान उपनाम बना सकते हैं। लेकिन सावधान रहें कि एक मैक मशीन पर GNU व्यवहार देशी कोरुटिल्स के साथ काम करने के लिए उपयोग किए जाने वाले अन्य लोगों के लिए भ्रमित हो सकता है, या आपके मैक सिस्टम पर अप्रत्याशित तरीके से व्यवहार कर सकता है।


0

मैंने OS X के लिए एक वास्तविक उपयोगिता लिखी है जो उसी तरह के परिणाम प्रदान कर सकती है readlink -f


यहाँ एक उदाहरण है:

(jalcazar@mac tmp)$ ls -l a
lrwxrwxrwx 1 jalcazar jalcazar 11  8 25 19:29 a -> /etc/passwd

(jalcazar@mac tmp)$ realpath a
/etc/passwd


यदि आप MacPorts का उपयोग कर रहे हैं, तो आप इसे निम्न कमांड के साथ इंस्टॉल कर सकते हैं sudo port selfupdate && sudo port install realpath:।


0

ट्रूली प्लेटफॉर्म-इंडपेंडेंट भी यही आर-ऑनलाइनर होगा

readlink(){ RScript -e "cat(normalizePath(commandArgs(T)[1]))" "$1";}

वास्तव में नकल करने के लिए readlink -f <path>, $ 1 के बजाय $ 2 का उपयोग करना होगा।


डिफ़ॉल्ट रूप से किसी सिस्टम पर R को छोड़कर शायद ही कोई हो। मैक पर नहीं अभी तक (10.15 के रूप में) जो यह सवाल है।
कोडनिफ़र

0

POSIX readlink -fशैल लिपियों के लिए POSIX अनुरूप कार्यान्वयन

https://github.com/ko1nksm/readlinkf

यह पोसिक्स कंप्लेंट (कोई बैशीवाद) नहीं है। यह न तो उपयोग करता है और न readlinkही realpath। मैंने सत्यापित किया है कि यह GNU के साथ तुलना करके ठीक वैसा ही है readlink -f( परीक्षा परिणाम देखें )। इसमें एरर हैंडलिंग और अच्छा प्रदर्शन है। आप सुरक्षित रूप से बदल सकते हैं readlink -f। लाइसेंस CC0 है, इसलिए आप इसे किसी भी परियोजना के लिए उपयोग कर सकते हैं।

# POSIX compliant version
readlinkf_posix() {
  [ "${1:-}" ] || return 1
  target=$1 max_symlinks=10 CDPATH=''

  [ -e "${target%/}" ] || target=${1%"${1##*[!/]}"} # trim trailing slashes
  [ -d "${target:-/}" ] && target="$target/"

  cd -P . 2>/dev/null || return 1
  while [ "$max_symlinks" -gt 0 ] && max_symlinks=$((max_symlinks - 1)); do
    if [ ! "$target" = "${target%/*}" ]; then
      cd -P "${target%/*}/" 2>/dev/null || break
      target=${target##*/}
    fi

    if [ ! -L "$target" ]; then
      target="${PWD%/}${target:+/}$target"
      printf '%s\n' "${target:-/}"
      return 0
    fi

    # `ls -dl` format: "%s %u %s %s %u %s %s -> %s\n",
    #   <file mode>, <number of links>, <owner name>, <group name>,
    #   <size>, <date and time>, <pathname of link>, <contents of link>
    # https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html
    link=$(ls -dl "$target" 2>/dev/null) || break
    target=${link#*" $target -> "}
  done
  return 1
}

कृपया नवीनतम कोड देखें। यह कुछ तय हो सकता है।


-2

पर्ल में एक रीडलिंक फ़ंक्शन है (जैसे मैं पर्ल में प्रतीकात्मक लिंक की प्रतिलिपि कैसे बनाऊं ? )। यह OS X सहित अधिकांश प्लेटफार्मों पर काम करता है:

perl -e "print readlink '/path/to/link'"

उदाहरण के लिए:

$ mkdir -p a/b/c
$ ln -s a/b/c x
$ perl -e "print readlink 'x'"
a/b/c

5
यह विकल्प के readlinkबिना भी ऐसा ही करता है -f- कोई पुनरावृत्ति, कोई निरपेक्ष मार्ग नहीं है - इसलिए आप readlinkसीधे उपयोग कर सकते हैं।
21

-2

@ कीथ स्मिथ का जवाब अनंत लूप देता है।

यहाँ मेरा जवाब है, जो मैं केवल SunOS (SunOS मिस इतना POSIX और GNU कमांड) पर उपयोग करता हूँ।

यह एक स्क्रिप्ट फ़ाइल है जिसे आपको अपनी $ PATH निर्देशिकाओं में से एक में रखना है:

#!/bin/sh
! (($#)) && echo -e "ERROR: readlink <link to analyze>" 1>&2 && exit 99

link="$1"
while [ -L "$link" ]; do
  lastLink="$link"
  link=$(/bin/ls -ldq "$link")
  link="${link##* -> }"
  link=$(realpath "$link")
  [ "$link" == "$lastlink" ] && echo -e "ERROR: link loop detected on $link" 1>&2 && break
done

echo "$link"


-5

मेरे सिस्टम और आपके बीच रीडलिंक के रास्ते अलग हैं। कृपया पूर्ण पथ निर्दिष्ट करने का प्रयास करें:

/sw/sbin/readlink -f


1
और क्या - वास्तव में - / sw / sbin और / usr / bin में अंतर है? और दो बायनेरिज़ अलग क्यों हैं?
ट्रिनकेन

4
अहा .. तो फ़िंक में एक प्रतिस्थापन है readlink कि ग्नू संगत है। यह जानना अच्छा है, लेकिन यह मेरी समस्या का समाधान नहीं करता है, क्योंकि मुझे अपनी स्क्रिप्ट को अन्य लोगों की मशीन पर चलाने की आवश्यकता है, और मुझे उनके लिए फ़िंक स्थापित करने की आवश्यकता नहीं है।
troelskn

आप मूल प्रश्न का उत्तर नहीं दे रहे हैं। कृपया अपना उत्तर पुनः लिखें।
जेम हैब्टलजेल 17
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.