দুটি পাথের মধ্যে আপেক্ষিক লিঙ্ক প্রাপ্তি


21

বলুন আমার দুটি পথ রয়েছে: <source_path>এবং <target_path>। আমি আমার শেল (zsh) -এর মত স্বয়ংক্রিয়ভাবে খুঁজে বের করতে যদি প্রতিনিধিত্ব করতে একটি উপায় হবে <target_path>থেকে <source_path>একটি আপেক্ষিক পাথ হিসাবে।

যেমন ধরুন

  • <source_path> হয় /foo/bar/something
  • <target_path> হয় /foo/hello/world

ফলাফল হবে ../../hello/world

আমার এটি কেন দরকার:

আমি থেকে একটি সিম্বলিক লিঙ্ক তৈরি করতে চান প্রয়োজন <source_path>থেকে <target_path>একটি ব্যবহার আপেক্ষিক , সিম্বলিক লিঙ্ক যখনই সম্ভব যেহেতু অন্যথায় আমাদের সাম্বা সার্ভার যখন আমি উইন্ডোজ থেকে নেটওয়ার্কে এই ফাইলগুলিতে অ্যাক্সেস সঠিকভাবে ফাইল প্রদর্শন করা হয় না (আমি Sys প্রশাসক নই, ও ডন ' টি এই সেটিং উপর নিয়ন্ত্রণ আছে)

এটি ধরে নিলে <target_path>এবং <source_path>পরম পাথ, নিম্নলিখিতটি একটি নিখুঁত পাথের দিকে নির্দেশ করে একটি প্রতীকী লিঙ্ক তৈরি করে ।

ln -s <target_path> <source_path>

সুতরাং এটি আমার প্রয়োজনের জন্য কাজ করে না। শত শত ফাইলের জন্য আমার এটি করা দরকার, তাই আমি নিজে নিজে এটি ঠিক করতে পারি না।

কোনও শেল বিল্ট-ইন যে এটি যত্ন করে?


আপনি symlinksনিখুঁত লিঙ্কগুলিকে আপেক্ষিক রূপান্তর করতে ব্যবহার করতে পারেন ।
স্টাফেন চেজেলাস

@ স্টাফেনচাজেলাস কিভাবে? আপনি একটি উত্তর পোস্ট করে পোস্ট করতে পারেন?
টেরডন

উত্তর:


10

আপনি symlinksনিখুঁত পাথগুলিকে আপেক্ষিক রূপান্তর করতে কমান্ডটি ব্যবহার করতে পারেন :

/tmp$ mkdir -p 1/{a,b,c} 2
/tmp$ cd 2
/tmp/2$ ln -s /tmp/1/* .
/tmp/2$ ls -l
total 0
lrwxrwxrwx 1 stephane stephane 8 Jul 31 16:32 a -> /tmp/1/a/
lrwxrwxrwx 1 stephane stephane 8 Jul 31 16:32 b -> /tmp/1/b/
lrwxrwxrwx 1 stephane stephane 8 Jul 31 16:32 c -> /tmp/1/c/

আমরা নিখুঁত লিঙ্ক পেয়েছি, আসুন তাদের আপেক্ষিক রূপান্তর করুন:

/tmp/2$ symlinks -cr .
absolute: /tmp/2/a -> /tmp/1/a
changed:  /tmp/2/a -> ../1/a
absolute: /tmp/2/b -> /tmp/1/b
changed:  /tmp/2/b -> ../1/b
absolute: /tmp/2/c -> /tmp/1/c
changed:  /tmp/2/c -> ../1/c
/tmp/2$ ls -l
total 0
lrwxrwxrwx 1 stephane stephane 6 Jul 31 16:32 a -> ../1/a/
lrwxrwxrwx 1 stephane stephane 6 Jul 31 16:32 b -> ../1/b/
lrwxrwxrwx 1 stephane stephane 6 Jul 31 16:32 c -> ../1/c/

তথ্যসূত্র


ধন্যবাদ স্টিফেন এটি মূল সমস্যার সমাধান করে, তাই আমি গ্রহণ করেছি। এটি বলেছিল, এমন কিছু (যেমন একটি zsh ফাংশন) পাওয়া খুব ভাল হবে যা দুটি পাথ (উত্স এবং লক্ষ্য) নেয় এবং উত্স থেকে লক্ষ্য পর্যন্ত আপেক্ষিক পথটিকে আউটপুট করে দেয় (এখানে কোনও প্রতীকী লিঙ্ক নেই)। এটি শিরোনামে জিজ্ঞাসিত প্রশ্নও সমাধান করবে।
আমেলিও ওয়াজকেজ-রেইনা


24

realpathকমান্ডটি ব্যবহার করার চেষ্টা করুন ( জিএনইউর অংশ coreutils; > = 8.23 ), উদাহরণস্বরূপ:

realpath --relative-to=/foo/bar/something /foo/hello/world

আপনি যদি ম্যাকোস ব্যবহার করছেন তবে জিএনইউ সংস্করণটি ইনস্টল করুন: brew install coreutilsএবং ব্যবহার করুন grealpath

নোট করুন যে কমান্ডটি সফল হওয়ার জন্য উভয় পাথেরই অস্তিত্ব থাকা দরকার। আপনার যদি যাইহোক আপেক্ষিক পাথের প্রয়োজন হয় এমনকি যদি সেগুলির একটির অস্তিত্ব না থাকে তবে -m সুইচটি যুক্ত করুন।

আরও উদাহরণের জন্য, প্রত্যক্ষ পাথকে বর্তমান ডিরেক্টরি অনুসারে আপেক্ষিক পথে রূপান্তর দেখুন ।


আমি পেয়েছি realpath: unrecognized option '--relative-to=.':( রিয়েলপথ সংস্করণ 1.19
ফুক্লভ

@ LưuVĩnhPhúc আপনার জিএনইউ / লিনাক্স সংস্করণ ব্যবহার করা দরকার realpath। আপনার উপর MacOS হন, তাহলে মাধ্যমে ইনস্টল: brew install coreutils
কেনরব

না, আমি উবুন্টুতে আছি 14.04 এলটিএস
ফুক্লিভি

@ LưuVĩnhPhúc আমি realpath (GNU coreutils) 8.26যেখানে প্যারামিটার উপস্থিত রয়েছি । দেখুন: gnu.org/software/coreutils/relpath ডাবল চেক করুন যে আপনি কোনও এলিফ ব্যবহার করছেন না (যেমন চালানো \realpath), এবং কীভাবে আপনি সংস্করণটি ইনস্টল করতে পারেন coreutils
কেনারব


7

আমি মনে করি এই অজগর সমাধান (@ ইভানটাইটেলম্যানের উত্তর হিসাবে একই পোস্ট থেকে নেওয়া )ও উল্লেখযোগ্য। এটি আপনার যুক্ত করুন ~/.zshrc:

relpath() python -c 'import os.path, sys;\
  print os.path.relpath(sys.argv[1],sys.argv[2])' "$1" "${2-$PWD}"

তারপরে আপনি এটি করতে পারেন, উদাহরণস্বরূপ:

$ relpath /usr/local/share/doc/emacs /usr/local/share/fonts
../doc/emacs

@ স্টাফেনচাজেলাস এটি লিঙ্কিত উত্তর থেকে সরাসরি কপি পেস্ট। আমি পার্ল লোক এবং মূলত অজগর জানি না তাই কীভাবে ব্যবহার করতে হয় তা আমি জানি না sys.argv। পোস্ট করা কোডটি যদি ভুল হয় বা উন্নত করা যায় তবে আমার ধন্যবাদ দিয়ে এটিকে নির্দ্বিধায় মনে করুন।
টেরডন

@ স্টাফেন চ্যাজেলাস আমি এখন বুঝতে পেরেছি, সম্পাদনার জন্য ধন্যবাদ।
টেরডন

7

এটি যত্ন নিতে কোনও শেল বিল্টিন নেই। যদিও স্ট্যাক ওভারফ্লোতে আমি একটি সমাধান পেয়েছি । আমি সমাধানটি এখানে সামান্য সংশোধন করে অনুলিপি করেছি এবং এই উত্তরটিকে সম্প্রদায় উইকি হিসাবে চিহ্নিত করেছি।

relpath() {
    # both $1 and $2 are absolute paths beginning with /
    # $1 must be a canonical path; that is none of its directory
    # components may be ".", ".." or a symbolic link
    #
    # returns relative path to $2/$target from $1/$source
    source=$1
    target=$2

    common_part=$source
    result=

    while [ "${target#"$common_part"}" = "$target" ]; do
        # no match, means that candidate common part is not correct
        # go up one level (reduce common part)
        common_part=$(dirname "$common_part")
        # and record that we went back, with correct / handling
        if [ -z "$result" ]; then
            result=..
        else
            result=../$result
        fi
    done

    if [ "$common_part" = / ]; then
        # special case for root (no common path)
        result=$result/
    fi

    # since we now have identified the common part,
    # compute the non-common part
    forward_part=${target#"$common_part"}

    # and now stick all parts together
    if [ -n "$result" ] && [ -n "$forward_part" ]; then
        result=$result$forward_part
    elif [ -n "$forward_part" ]; then
        # extra slash removal
        result=${forward_part#?}
    fi

    printf '%s\n' "$result"
}

আপনি এই ফাংশনটি এর মতো ব্যবহার করতে পারেন:

source=/foo/bar/something
target=/foo/hello/world
ln -s "$(relpath "$source" "$target")" "$source"

3
# Prints out the relative path between to absolute paths. Trivial.
#
# Parameters:
# $1 = first path
# $2 = second path
#
# Output: the relative path between 1st and 2nd paths
relpath() {
    local pos="${1%%/}" ref="${2%%/}" down=''

    while :; do
        test "$pos" = '/' && break
        case "$ref" in $pos/*) break;; esac
        down="../$down"
        pos=${pos%/*}
    done

    echo "$down${ref##$pos/}"
}

এটিই সমস্যার সহজতম এবং সুন্দর সমাধান।

এছাড়াও এটি সমস্ত বোর্নের মতো শেলগুলিতে কাজ করা উচিত।

এবং এখানে জ্ঞান হ'ল: বাহ্যিক ইউটিলিটি বা এমনকি জটিল অবস্থার জন্য একেবারেই প্রয়োজন নেই। কিছু কিছু উপসর্গ / প্রত্যয়ের বিকল্প এবং কিছুক্ষণের জন্য লুপ হ'ল বোর্নের মতো শেলগুলিতে কেবল কিছু করা দরকার।

পেস্টবিনের মাধ্যমেও উপলব্ধ: http://pastebin.com/CtTfvime


আপনার সমাধানের জন্য ধন্যবাদ। আমি এটি দেখতে পেয়েছি যে এটির কাজ করার জন্য Makefileআমাকে লাইনে ডাবল উদ্ধৃতিগুলির একটি জোড়া যুক্ত করা দরকার pos=${pos%/*}(এবং অবশ্যই প্রতিটি লাইনের শেষে অর্ধিকোলন এবং ব্যাকস্ল্যাশ)।
সিরকনফ্লেক্স

আইডিয়া খারাপ না কিন্তু, মামলা বর্তমান সংস্করণ প্রচুর কাজ করে না: relpath /tmp /tmp, relpath /tmp /tmp/a, relpath /tmp/a /। যোগ করার সাথে সাথে, আপনি উল্লেখ করতে ভুলে /tmp/a/..
গেছেন

0

আমাকে বাশ স্ক্রিপ্ট লিখতে হয়েছিলএটি নির্ভরযোগ্যভাবে করার (এবং অবশ্যই ফাইল অস্তিত্ব যাচাই না করে)।

ব্যবহার

relpath <symlink path> <source path>

একটি আপেক্ষিক উত্স পথ ফেরত দেয়।

উদাহরণ:

#/a/b/c/d/e   ->  /a/b/CC/DD/EE       ->  ../../CC/DD/EE
relpath /a/b/c/d/e   /a/b/CC/DD/EE

#./a/b/c/d/e   ->  ./a/b/CC/DD/EE       ->  ../../CC/DD/EE
relpath ./a/b/c/d/e  ./a/b/CC/DD/EE

উভয় পেতে ../../CC/DD/EE


দ্রুত পরীক্ষা করার জন্য আপনি চালাতে পারেন

curl -sL https://github.com/jjqq2013/bash-scripts/raw/master/common/relpath | bash -s -- --test

ফলাফল: পরীক্ষার একটি তালিকা

/a             ->  /                 ->  .
/a/b           ->  /                 ->  ..
/a/b           ->  /a                ->  .
/a/b/c         ->  /a                ->  ..
/a/b/c         ->  /a/b              ->  .
/a/b/c         ->  /a/b/CC           ->  CC
/a/b/c/d/e     ->  /a                ->  ../../..
/a/b/c/d/e     ->  /a/b              ->  ../..
/a/b/c/d/e     ->  /a/b/CC           ->  ../../CC
/a/b/c/d/e     ->  /a/b/CC/DD/EE     ->  ../../CC/DD/EE
./a            ->  ./                ->  .
./a/b          ->  ./                ->  ..
./a/b          ->  ./a               ->  .
./a/b/c        ->  ./a               ->  ..
./a/b/c        ->  ./a/b             ->  .
./a/b/c        ->  ./a/b/CC          ->  CC
./a/b/c/d/e    ->  ./a               ->  ../../..
./a/b/c/d/e    ->  ./a/b/CC          ->  ../../CC
./a/b/c/d/e    ->  ./a/b/CC/DD/EE    ->  ../../CC/DD/EE
/a             ->  /x                ->  x
/a/b           ->  /x                ->  ../x
/a/b/c         ->  /x                ->  ../../x
/a             ->  /x/y              ->  x/y
/a/b           ->  /x/y              ->  ../x/y
/a/b/c         ->  /x/y              ->  ../../x/y
/x             ->  /a                ->  a
/x             ->  /a/b              ->  a/b
/x             ->  /a/b/c            ->  a/b/c
/x/y           ->  /a                ->  ../a
/x/y           ->  /a/b              ->  ../a/b
/x/y           ->  /a/b/c            ->  ../a/b/c
./a a/b/c/d/e  ->  ./a a/b/CC/DD/EE  ->  ../../CC/DD/EE
/x x/y y       ->  /a a/b b/c c      ->  ../a a/b b/c c

বিটিডাব্লু, আপনি যদি এই স্ক্রিপ্টটি সংরক্ষণ না করেই ব্যবহার করতে চান এবং আপনি এই স্ক্রিপ্টটিতে বিশ্বাস করেন, তবে ব্যাশ ট্রিক দিয়ে আপনার কাছে দুটি উপায় থাকতে পারে।

relpathকমান্ড অনুসরণ করে বাশ ফাংশন হিসাবে আমদানি করুন । (বাশ 4+ প্রয়োজন)

source <(curl -sSL https://github.com/jjqq2013/bash-scripts/raw/master/common/relpath)

বা স্ক্রিপ্টটিকে কল-বাশ কম্বো সহ ফ্লাইটটিকে কল করুন।

curl -sSL https://github.com/jjqq2013/bash-scripts/raw/master/common/relpath | bash -s -- /a/b/c/d/e /a/b/CC/DD/EE
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.