শেল স্ক্রিপ্টে প্রতীকী লিঙ্কগুলি কীভাবে সমাধান করবেন


220

একটি নিখুঁত বা আপেক্ষিক পাথ (ইউনিক্সের মতো সিস্টেমে) দেওয়া, আমি কোনও মধ্যবর্তী সিমলিংকগুলি সমাধান করার পরে লক্ষ্যটির সম্পূর্ণ পথ নির্ধারণ করতে চাই। একইসাথে ~ ব্যবহারকারীর নাম স্বাক্ষর করার জন্য বোনাস পয়েন্ট।

লক্ষ্যটি যদি ডিরেক্টরি হয় তবে ডিরেক্টরিতে chdir () এবং তারপরে getcwd () কল করা সম্ভব হতে পারে তবে আমি সি হেল্পার লেখার চেয়ে শেল স্ক্রিপ্ট থেকে সত্যিই এটি করতে চাই। দুর্ভাগ্যক্রমে, শেলগুলির ব্যবহারকারীর কাছ থেকে সিমলিংকের অস্তিত্বকে আড়াল করার চেষ্টা করার প্রবণতা রয়েছে (এটি ওএস এক্স-তে বাশ):

$ ls -ld foo bar
drwxr-xr-x   2 greg  greg  68 Aug 11 22:36 bar
lrwxr-xr-x   1 greg  greg   3 Aug 11 22:36 foo -> bar
$ cd foo
$ pwd
/Users/greg/tmp/foo
$

আমি যা চাই তা একটি ফাংশন রেজোলিউশন (যেমন) উপরের উদাহরণে tmp ডিরেক্টরি থেকে চালিত হলে, সমাধান করুন ("foo") == "/ ব্যবহারকারী / গ্রেগ / tmp / বার"।

উত্তর:


92

মান অনুসারে, সমাধান pwd -Pহওয়া সিমলিংকের সাথে পথটি ফিরে আসা উচিত।

সি ক্রিয়াকলাপ char *getcwd(char *buf, size_t size)থেকে unistd.hএকই আচরণ হওয়া উচিত।

getcwd pwd


22
এটি কেবল (বর্তমান) ডিরেক্টরিতে কাজ করে? লক্ষ্য যদি কোনও ফাইল হয় তবে তা কিছুই দেয় না ...
ডালা

4
লিংকটি ভাঙ্গা থাকলে কাজ করে না কারণ আপনি এটিকে আপনার বর্তমান পথ হিসাবে তৈরি করতে পারবেন না
টম হাওয়ার্ড

6
অন্ধত্বের উপকারের সংক্ষিপ্তসার হিসাবে: এই উত্তরটি কেবল খুব সীমাবদ্ধ পরিস্থিতিতে কাজ করে, অর্থাত্ যদি আগ্রহের সিমিলিংকটি এমন কোনও ডিরেক্টরিতে থাকে যা আসলে উপস্থিত থাকে ; প্লাস, cdকল করার আগে আপনাকে অবশ্যই প্রথমে এটি করতে হবে pwd -P। অন্য কথায়: এটা আপনার সমাধান করতে (লক্ষ্য দেখুন) symlinks মঞ্জুরি দেয় না ফাইলগুলিতে অথবা ভাঙা symlinks এবং বিদ্যমান-ডিরেক্টরি symlinks আপনি অতিরিক্ত কাজ করতে হবে নিরসনের জন্য (পূর্ববর্তী পরিশ্রমী Dir পুনঃস্থাপন বা স্থানীয়করণ cdএবং pwd -Pকল একটি সাবসিলে)
mklement0

খারাপের জন্য আমি কোনও ফাইল নয় একটি ডিরেক্টরি সমাধান করার উপায় খুঁজছি।
মার্টিন

অন্যরা যেমন উল্লেখ করেছে, এটি সত্যই প্রশ্নের উত্তর দেয় না। @ পিক্সেলবিটের উত্তর নীচে দেয়।
এরস্ট্যাপলস

401
readlink -f "$path"

সম্পাদকের দ্রষ্টব্য: উপরেরগুলি জিএনইউ readlink এবং ফ্রিবিএসডি / পিসি-বিএসডি / ওপেনবিএসডি নিয়ে কাজ করে readlink , তবে ওএস এক্সে 10.11 হিসাবে কাজ করে না
জিএনইউ readlink অতিরিক্ত, সম্পর্কিত বিকল্পগুলি সরবরাহ করে যেমন -mচূড়ান্ত লক্ষ্য উপস্থিত রয়েছে কিনা তা একটি সিমিলিংক সমাধানের জন্য।

নোট করুন যেহেতু জিএনইউ কোর্টিলগুলি ৮.১৫ (২০১২-০১-০6) থেকে রয়েছে, সেখানে একটি রিয়েলপথ প্রোগ্রাম রয়েছে যা উপরের তুলনায় কম অবসেস এবং আরও নমনীয়। এটি একই নামের ফ্রিবিএসডি ব্যবহারের সাথেও সামঞ্জস্যপূর্ণ। এটি দুটি ফাইলের মধ্যে একটি আপেক্ষিক পথ উত্পন্ন করার কার্যকারিতাও অন্তর্ভুক্ত করে।

realpath $path

[ হলিউলিওর মন্তব্য থেকে নীচে প্রশাসনিক সংযোজন - ড্যানর্টন]

ম্যাক ওএস এক্সের জন্য (কমপক্ষে 10.11.x এর মাধ্যমে) বিকল্প readlinkছাড়াই ব্যবহার করুন -f:

readlink $path

সম্পাদকের দ্রষ্টব্য: এটি প্রতীকগুলি পুনরাবৃত্তিমূলকভাবে সমাধান করবে না এবং চূড়ান্ত লক্ষ্যটির প্রতিবেদন করবে না ; উদাহরণস্বরূপ, প্রদত্ত syMLinka যা নির্দেশ করে b, যার পরিবর্তে পয়েন্টগুলি নির্দেশ করে c, এটি কেবলমাত্র রিপোর্ট bকরবে (এবং এটি নিশ্চিত করবে না যে এটি পরম পথ হিসাবে আউটপুট কিনা )। অনুপস্থিত কার্যকারিতার ফাঁক পূরণ করতে ওএস এক্স-
এ নিম্নলিখিত perlকমান্ডটি ব্যবহার করুন readlink -f:
perl -MCwd -le 'print Cwd::abs_path(shift)' "$path"


5
এই Mac OS X কাজ করে না - দেখুন stackoverflow.com/questions/1055671/...
Bkkbrad

1
ওএস এক্সের অসঙ্গতি সম্পর্কে লজ্জা, অন্যথায় দুর্দান্ত +1
জেপিপি

11
ওএস এক্স-এ আপনি হোমব্রু দিয়ে কোর্টিল ইনস্টল করতে পারেন। এটি এটিকে "গ্রালপাথ" হিসাবে ইনস্টল করে।
কেইফ

10
readlinkউপর ওএসএক্স কাজ করে, কিন্তু অন্য সিনট্যাক্স দরকার: readlink $path ছাড়া-f
হলিও

2
রিডলিঙ্কটি একাধিক স্তর সিমিলিংকের ডি-রেফারেন্সে ব্যর্থ হয়েছে যদিও এটি একবারে কেবল একটি স্তরকে মর্যাদা দেয়
ম্যাগনাস

26

"pwd -P" আপনাকে কেবল ডিরেক্টরিটি চাইলে কাজ করতে পারে বলে মনে হয়, তবে যদি কোনও কারণে আপনি প্রকৃত এক্সিকিউটেবলের নাম চান তবে আমি মনে করি না এটি সাহায্য করে। এখানে আমার সমাধান:

#!/bin/bash

# get the absolute path of the executable
SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0")

# resolve symlinks
while [[ -h $SELF_PATH ]]; do
    # 1) cd to directory of the symlink
    # 2) cd to the directory of where the symlink points
    # 3) get the pwd
    # 4) append the basename
    DIR=$(dirname -- "$SELF_PATH")
    SYM=$(readlink "$SELF_PATH")
    SELF_PATH=$(cd "$DIR" && cd "$(dirname -- "$SYM")" && pwd)/$(basename -- "$SYM")
done

17

আমার প্রিয় একটি realpath foo

রিয়েলপথ - ক্যানোনিকালাইজড পরম পথের নামটি ফিরিয়ে দিন

রিয়েলপথ সমস্ত প্রতীকী লিঙ্কগুলি প্রসারিত করে এবং '/.//', '/..//' এবং অতিরিক্ত '/' অক্ষরগুলিকে পথের নাম অনুসারে নাল টার্মিনেটেড স্ট্রিংয়ের সমাধান করে and
       সংশোধন_পথ দ্বারা নামী PATH_MAX আকারের বাফারে ক্যানোনিকালাইজড পরম পথের নাম সংরক্ষণ করে। ফলস্বরূপ পাথের কোনও প্রতীকী লিঙ্ক থাকবে না, '/./' বা
       '/../' উপাদান।

ডেবিয়ানে (ইচ এবং পরে) এই কমান্ডটি রিয়েলপথ প্যাকেজে উপলব্ধ।
ফিল রস

2
রিয়েলপথ এখন (জানুয়ারী ২০১২) কোরিউটিলের অংশ এবং পিছনে
ডিবিয়ান

1
আমি না realpathসঙ্গে গনুহ 8.4.31 coreutils CentOS 6। আমি বেশ কয়েকটি অন্যদের জুড়ে করেছি ইউনিক্স ও লিনাক্স আছে একটি গনুহ coreutils প্যাকেজ ছাড়া realpath । সুতরাং এটি কেবল সংস্করণের চেয়ে বেশি নির্ভর করে বলে মনে হচ্ছে।
টক্সালোট

আমি realpathতার চেয়ে বেশি পছন্দ করি readlinkকারণ এটি বিকল্প পতাকা যেমন অফার করে--relative-to
arr_sea

10
readlink -e [filepath]

আপনি যা চেয়েছিলেন ঠিক তা-ই মনে হচ্ছে - এটি একটি আরবেরির পাথ গ্রহণ করে, সমস্ত প্রতীককে সমাধান করে এবং "বাস্তব" পথটি ফিরিয়ে দেয় - এবং এটি "স্ট্যান্ডার্ড * নিক্স" সম্ভবত সমস্ত সিস্টেম ইতিমধ্যে রয়েছে


শুধু এটি দ্বারা দংশিত হয়েছে। এটি ম্যাকের সাথে কাজ করে না এবং আমি প্রতিস্থাপনের জন্য অনুসন্ধান করছি।
hillিল

5

অন্য উপায়:

# Gets the real path of a link, following all links
myreadlink() { [ ! -h "$1" ] && echo "$1" || (local link="$(expr "$(command ls -ld -- "$1")" : '.*-> \(.*\)$')"; cd $(dirname $1); myreadlink "$link" | sed "s|^\([^/].*\)\$|$(dirname $1)/\1|"); }

# Returns the absolute path to a command, maybe in $PATH (which) or not. If not found, returns the same
whereis() { echo $1 | sed "s|^\([^/].*/.*\)|$(pwd)/\1|;s|^\([^/]*\)$|$(which -- $1)|;s|^$|$1|"; } 

# Returns the realpath of a called command.
whereis_realpath() { local SCRIPT_PATH=$(whereis $1); myreadlink ${SCRIPT_PATH} | sed "s|^\([^/].*\)\$|$(dirname ${SCRIPT_PATH})/\1|"; } 

আমার মাইরিডলিংক () এ সিডি দরকার, কারণ এটি একটি পুনরাবৃত্ত ফাংশন, এটি কোনও লিঙ্ক না পাওয়া পর্যন্ত প্রতিটি ডিরেক্টরিতে যায়। যদি এটি কোনও লিঙ্ক খুঁজে পায়, রিয়েলপথটি ফিরিয়ে দেয় এবং তারপরে সেডটি প্রতিস্থাপন করবে।
কীমন 21

5

বেশিরভাগ সিস্টেমে রিডলিংক উপলব্ধ রয়েছে তা জেনেও প্রদত্ত কয়েকটি সমাধান একসাথে রেখে, ওএসএক্স এবং ডেবিয়ানের ক্ষেত্রে এটি আমার পক্ষে ভাল কাজ করে। আমি বিএসডি সিস্টেম সম্পর্কে নিশ্চিত নই। শর্তটি কেবল ওএসএক্স থেকে [[ $OSTYPE != darwin* ]]বাদ দেওয়ার দরকার হতে পারে -f

#!/bin/bash
MY_DIR=$( cd $(dirname $(readlink `[[ $OSTYPE == linux* ]] && echo "-f"` $0)) ; pwd -P)
echo "$MY_DIR"

3

এখানে কোনও ইনলাইন পার্ল স্ক্রিপ্ট ব্যবহার করে ম্যাকস / ইউনিক্সে ফাইলটির আসল পথটি কীভাবে পাওয়া যায় তা এখানে:

FILE=$(perl -e "use Cwd qw(abs_path); print abs_path('$0')")

একইভাবে, সিমলিঙ্কযুক্ত ফাইলের ডিরেক্টরি পেতে:

DIR=$(perl -e "use Cwd qw(abs_path); use File::Basename; print dirname(abs_path('$0'))")

3

আপনার পথটি একটি ডিরেক্টরি, বা এটি একটি ফাইল হতে পারে? যদি এটি ডিরেক্টরি হয় তবে এটি সহজ:

(cd "$DIR"; pwd -P)

তবে এটি যদি কোনও ফাইল হতে পারে তবে এটি কাজ করবে না:

DIR=$(cd $(dirname "$FILE"); pwd -P); echo "${DIR}/$(readlink "$FILE")"

কারণ সিমলিংকটি কোনও আপেক্ষিক বা পুরো পথে সমাধান করতে পারে।

স্ক্রিপ্টগুলিতে আমার আসল পথটি সন্ধান করা দরকার, যাতে আমি কনফিগারেশন বা এটির সাথে ইনস্টল করা অন্যান্য স্ক্রিপ্টগুলি উল্লেখ করতে পারি, আমি এটি ব্যবহার করি:

SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
  DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
  SOURCE="$(readlink "$SOURCE")"
  [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done

আপনি SOURCEযে কোনও ফাইলের পথে সেট করতে পারেন । মূলত, যতক্ষণ পাথটি একটি সিমিলিংক থাকে ততক্ষণ এটি সেই সিমলিংকটিকে সমাধান করে। কৌশলটি লুপের শেষ লাইনে রয়েছে। যদি সমাধান করা সিমিলিংক নিখুঁত হয় তবে এটি এটি হিসাবে ব্যবহার করবে SOURCE। তবে এটি যদি আপেক্ষিক হয় তবে এটি এর জন্য প্রিপেন্ড DIRকরবে, যা আমি প্রথমে বর্ণনা করা সহজ ট্রিক দ্বারা বাস্তবে পরিণত হয়েছিল।


2
function realpath {
    local r=$1; local t=$(readlink $r)
    while [ $t ]; do
        r=$(cd $(dirname $r) && cd $(dirname $t) && pwd -P)/$(basename $t)
        t=$(readlink $r)
    done
    echo $r
}

#example usage
SCRIPT_PARENT_DIR=$(dirname $(realpath "$0"))/..

এটি (ক) হোয়াইটস্পেস বা শেল মেটাচার্যাক্টর এবং (খ) ভাঙা প্রতিলিঙ্কযুক্ত কোনও পথ (যা আপনি কেবল চলমান স্ক্রিপ্টের পিতামূলক পথ চান, এটি ধরে নিলে (ক) প্রযোজ্য নয়) ভঙ্গ হবে।
mklement0

যদি আপনি শ্বেত স্পেস ব্যবহারের উক্তি নিয়ে উদ্বিগ্ন হন।
ডেভ

দয়া করে করুন - যদিও এটি (বি) ঠিকানা দেবে না।
mklement0

দয়া করে আমাকে খ এর একটি উদাহরণ দেখান) যেখানে এটি ব্যর্থ হয়। সংজ্ঞা অনুসারে, একটি ভাঙা সিমলিংক একটি ডিরেক্টরি প্রবেশের দিকে নির্দেশ করে যা বিদ্যমান নেই। এই স্ক্রিপ্টের মূল বিষয়টি হ'ল অন্য দিকের সিমলিংকগুলি সমাধান করা। যদি সিমলিংকটি নষ্ট হয়ে যায় তবে আপনি স্ক্রিপ্টটি চালাবেন না। এই উদাহরণটি বর্তমানে সম্পাদনকারী স্ক্রিপ্টটি সমাধান করার চেষ্টা করে।
ডেভ

"বর্তমানে সম্পাদনকারী স্ক্রিপ্টের সমাধানের জন্য বুদ্ধিমানের উদ্দেশ্য" - প্রকৃতপক্ষে, যা আপনি প্রশ্নটির সুযোগকে সংকীর্ণ করার জন্য বেছে নিয়েছেন যা আপনি ফোকাস করতে বেছে নিয়েছেন; এটি পুরোপুরি ঠিক আছে, যতক্ষণ আপনি এটি বলেন। যেহেতু আপনি করেন নি, আমি এটি আমার মন্তব্যে জানিয়েছি। উদ্ধৃতি ইস্যুটি ঠিক করুন, যা উত্তরের ক্ষেত্র নির্বিশেষে একটি সমস্যা।
mklement0

2

দ্রষ্টব্য: আমি বিশ্বাস করি এটি একটি শক্ত, পোর্টেবল, রেডিমেড সলিউশন বলে বিশ্বাস করি, যা সেই কারণেই প্রায় দীর্ঘ

নীচে একটি সম্পূর্ণ পসিক্স-কমপ্লায়েন্ট স্ক্রিপ্ট / ফাংশন রয়েছে যেহেতু ক্রস প্ল্যাটফর্ম (ম্যাকোজেও কাজ করে, readlinkএখনও -f10.12 (সিয়েরা) হিসাবে সমর্থন করে না ) - এটি কেবল পসিক্স শেল ভাষার বৈশিষ্ট্য এবং কেবল পসিক্স-কমপ্লায়েন্ট ইউটিলিটি কল ব্যবহার করে ।

এটি জিএনইউ'র (এর কঠোর সংস্করণ ) পোর্টেবল বাস্তবায়নreadlink -ereadlink -f

আপনি করতে পারেন চালানোর স্ক্রিপ্ট সঙ্গেsh বা উৎস ফাংশন মধ্যে bash, kshএবংzsh :

উদাহরণস্বরূপ, কোনও স্ক্রিপ্টের অভ্যন্তরে আপনি চালনার স্ক্রিপ্টটিকে সত্যিকারের ডিরেক্টরি উত্সের জন্য সিমলিঙ্কগুলি সমাধান করার জন্য এটি ব্যবহার করতে পারেন:

trueScriptDir=$(dirname -- "$(rreadlink "$0")")

rreadlink স্ক্রিপ্ট / ফাংশন সংজ্ঞা:

এই উত্তরটি থেকে কৃতজ্ঞতার সাথে কোডটি মানিয়ে নেওয়া হয়েছিল ।
আমি এখানে একটি bashবেসড স্ট্যান্ড-একা ইউটিলিটি সংস্করণও তৈরি করেছি , যা আপনি নোড.জেস ইনস্টলড থাকলে ইনস্টল করতে পারেন can
npm install rreadlink -g

#!/bin/sh

# SYNOPSIS
#   rreadlink <fileOrDirPath>
# DESCRIPTION
#   Resolves <fileOrDirPath> to its ultimate target, if it is a symlink, and
#   prints its canonical path. If it is not a symlink, its own canonical path
#   is printed.
#   A broken symlink causes an error that reports the non-existent target.
# LIMITATIONS
#   - Won't work with filenames with embedded newlines or filenames containing 
#     the string ' -> '.
# COMPATIBILITY
#   This is a fully POSIX-compliant implementation of what GNU readlink's
#    -e option does.
# EXAMPLE
#   In a shell script, use the following to get that script's true directory of origin:
#     trueScriptDir=$(dirname -- "$(rreadlink "$0")")
rreadlink() ( # Execute the function in a *subshell* to localize variables and the effect of `cd`.

  target=$1 fname= targetDir= CDPATH=

  # Try to make the execution environment as predictable as possible:
  # All commands below are invoked via `command`, so we must make sure that
  # `command` itself is not redefined as an alias or shell function.
  # (Note that command is too inconsistent across shells, so we don't use it.)
  # `command` is a *builtin* in bash, dash, ksh, zsh, and some platforms do not 
  # even have an external utility version of it (e.g, Ubuntu).
  # `command` bypasses aliases and shell functions and also finds builtins 
  # in bash, dash, and ksh. In zsh, option POSIX_BUILTINS must be turned on for
  # that to happen.
  { \unalias command; \unset -f command; } >/dev/null 2>&1
  [ -n "$ZSH_VERSION" ] && options[POSIX_BUILTINS]=on # make zsh find *builtins* with `command` too.

  while :; do # Resolve potential symlinks until the ultimate target is found.
      [ -L "$target" ] || [ -e "$target" ] || { command printf '%s\n' "ERROR: '$target' does not exist." >&2; return 1; }
      command cd "$(command dirname -- "$target")" # Change to target dir; necessary for correct resolution of target path.
      fname=$(command basename -- "$target") # Extract filename.
      [ "$fname" = '/' ] && fname='' # !! curiously, `basename /` returns '/'
      if [ -L "$fname" ]; then
        # Extract [next] target path, which may be defined
        # *relative* to the symlink's own directory.
        # Note: We parse `ls -l` output to find the symlink target
        #       which is the only POSIX-compliant, albeit somewhat fragile, way.
        target=$(command ls -l "$fname")
        target=${target#* -> }
        continue # Resolve [next] symlink target.
      fi
      break # Ultimate target reached.
  done
  targetDir=$(command pwd -P) # Get canonical dir. path
  # Output the ultimate target's canonical path.
  # Note that we manually resolve paths ending in /. and /.. to make sure we have a normalized path.
  if [ "$fname" = '.' ]; then
    command printf '%s\n' "${targetDir%/}"
  elif  [ "$fname" = '..' ]; then
    # Caveat: something like /var/.. will resolve to /private (assuming /var@ -> /private/var), i.e. the '..' is applied
    # AFTER canonicalization.
    command printf '%s\n' "$(command dirname -- "${targetDir}")"
  else
    command printf '%s\n' "${targetDir%/}/$fname"
  fi
)

rreadlink "$@"

সুরক্ষার উপর একটি স্পর্শক:

জার্নো , commandএকই নামটির কোনও উপন্যাস বা শেল ফাংশন দ্বারা বিল্টিন ছায়াবিভক্ত নয় তা নিশ্চিত করে ফাংশনটির প্রসঙ্গে একটি মন্তব্যে জিজ্ঞাসা করেছে:

যদি unaliasবা হয় unsetএবং [এলিয়াস বা শেল ফাংশন হিসাবে সেট করা হয়?

এর আসল অর্থ রয়েছে কিনা তা rreadlinkনিশ্চিত করার পিছনে অনুপ্রেরণা commandহ'ল এটিকে ব্যবহারের (সৌম্য) সুবিধাগুলি বাইপাস এবং ফাংশনগুলি প্রায়শই ইন্টারেক্টিভ শেলগুলিতে স্ট্যান্ডার্ড কমান্ডের ছায়া হিসাবে ব্যবহৃত হয়, যেমন lsপছন্দসই বিকল্পগুলি অন্তর্ভুক্ত করার জন্য পুনরায় সংজ্ঞায়িত করা।

আমার মনে হয় এটা বলতে চাই যে কোনো অবিশ্বস্ত, দূষিত পরিবেশ সাথে এসেছেন ডিলিং যদি না আপনি প্রায় উদ্বেজক নিরাপদ unaliasবা unset- বা, যে বিষয়টি জন্য, while, doএকটি উদ্বেগের বিষয় নতুনভাবে সংজ্ঞায়িত করা হচ্ছে না -, ...।

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

আপনার উদ্বেগকে বিশেষভাবে সমাধান করতে:

ফাংশন নির্ভর করে unaliasএবং unsetতাদের আসল অর্থ রাখে। তাদের শেল ফাংশন হিসাবে এমনভাবে পুনরায় সংজ্ঞায়িত করা যাতে তাদের আচরণের পরিবর্তন ঘটে; একটি হিসাবে redefinition ওরফে না অগত্যা একটি উদ্বেগের বিষয়, কারণ মূল্য উদ্ধৃতি (অংশ) কমান্ড নাম (যেমন, \unalias) alias লেখা রোধ করা যাবে।

যাইহোক, মূল্য উদ্ধৃতি হয় না শেল জন্য একটি বিকল্প কীওয়ার্ড ( while, for, if, do, ...) এবং শেল কীওয়ার্ড শেল বেশি প্রাধান্য গ্রহণ না যখন ফাংশন , ইন bashএবং zshalias লেখা তাই শেল-শব্দ redefinitions আপনি চালাতে হবে সতর্ক, সর্বোচ্চ প্রাধান্য আছে unaliasসঙ্গে তাদের নামগুলি (যদিও অ-ইন্টারেক্টিভ bash শেলগুলিতে (যেমন স্ক্রিপ্ট হিসাবে) এলিয়াসগুলি ডিফল্টরূপে প্রসারিত হয় না - তবে কেবল shopt -s expand_aliasesপ্রথমে স্পষ্টভাবে বলা হয়)।

unaliasএকটি বিল্টিন হিসাবে - এর আসল অর্থ রয়েছে তা নিশ্চিত করার জন্য আপনাকে \unsetপ্রথমে এটি ব্যবহার করতে হবে , যার প্রয়োজন unsetএর মূল অর্থ:

unsetএটি একটি শেল অন্তর্নির্মিত , যাতে এটি যেমন প্রেরিত হয় তা নিশ্চিত করার জন্য, আপনাকে নিশ্চিত করতে হবে যে এটি নিজেই কোনও ফাংশন হিসাবে পুনরায় সংজ্ঞায়িত হয়নি । আপনি উদ্ধৃতি দিয়ে একটি উপনাম ফর্মটি বাইপাস করতে পারবেন, আপনি শেল-ফাংশন ফর্মটি বাইপাস করতে পারবেন না - 22 ধরুন।

সুতরাং, যতক্ষণ না আপনি unsetতার মূল অর্থের উপর নির্ভর করতে পারবেন না, আমি যা বলতে পারি তা থেকে, সমস্ত দূষিত পুনর্নির্ধারার বিরুদ্ধে রক্ষার কোনও গ্যারান্টিযুক্ত উপায় নেই।


আমার অভিজ্ঞতা অনুসারে, আপনি প্রথমে যা বলছেন তার বিপরীতে উপন্যাসগুলি বাইপাস করা হয়, শেল ফাংশন নয়।
জার্নো

আমি পরীক্ষা করেছিলাম যে আমি একটি শাম ফাংশন ইন এবং এর হিসাবে এবং [একটি সংজ্ঞা হিসাবে সংজ্ঞা দিতে পারি । dashbashbash
জার্নো

1
আমি আমার বিষয়টি আলাদা প্রশ্ন হিসাবে তৈরি করেছি ।
জার্নো

@ জার্নো: ভাল পয়েন্ট; আমি আমার উত্তর আপডেট করেছি; আপনি যদি মনে করেন এখনও সমস্যা আছে তবে আমাকে জানান।
mklement0

1
@jarno: আপনি করতে পারেন সংজ্ঞায়িত whileএকটি ফাংশন হিসাবে bash, kshএবং zsh(কিন্তু dash, কিন্তু শুধুমাত্র সঙ্গে) function <name>শব্দবিন্যাস: function while { echo foo; }কাজ ( while() { echo foo; }না)। যাইহোক, এই অভ্যস্ত 'ছায়া while শব্দ , কারণ কীওয়ার্ড ফাংশন বেশী প্রাধান্য (এই ফাংশন হিসাবে ডাকা একমাত্র উপায় আছে \while)। ইন bashএবং zsh, alias লেখা কীওয়ার্ড বেশী প্রাধান্য, তাই আছে ওরফে কীওয়ার্ড redefinitions (কিন্তু তাদের ছায়া না bashশুধুমাত্র ডিফল্টরূপে ইন্টারেক্টিভ , শাঁস যদি না shopt -s expand_aliasesস্পষ্টভাবে বলা হয়)।
mklement0

1

সাধারণ শেল স্ক্রিপ্টগুলিতে প্রায়শই তাদের "হোম" ডিরেক্টরিটি সিমলিংক হিসাবে ডাকা হলেও তাদের সন্ধান করতে হয় to স্ক্রিপ্টটি এই মাত্র "0" থেকে তাদের "আসল" অবস্থানটি সন্ধান করতে হবে।

cat `mvn`

আমার সিস্টেমে নীচে থাকা একটি স্ক্রিপ্ট প্রিন্ট করে, যা আপনার যা প্রয়োজন তা সম্পর্কে একটি ভাল ইঙ্গিত হওয়া উচিত।

if [ -z "$M2_HOME" ] ; then
  ## resolve links - $0 may be a link to maven's home
  PRG="$0"

  # need this for relative symlinks
  while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '/.*' > /dev/null; then
      PRG="$link"
    else
      PRG="`dirname "$PRG"`/$link"
    fi
  done

  saveddir=`pwd`

  M2_HOME=`dirname "$PRG"`/..

  # make it fully qualified
  M2_HOME=`cd "$M2_HOME" && pwd`

1

এটা চেষ্টা কর:

cd $(dirname $([ -L $0 ] && readlink -f $0 || echo $0))

1

যেহেতু আমি বছরের পর বছর ধরে এটি বহুবার ছড়িয়েছি, এবং এবার আমার ওএসএক্স এবং লিনাক্সে ব্যবহার করতে পারি এমন একটি খাঁটি বাশ বহনযোগ্য সংস্করণ প্রয়োজন, তাই আমি এগিয়ে গিয়ে একটি লিখেছিলাম:

জীবিত সংস্করণ এখানে বাস করে:

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

তবে এস-এর স্বার্থে, এখানে বর্তমান সংস্করণটি রয়েছে (আমার মনে হয় এটি ভালভাবে পরীক্ষা করা হয়েছে ... তবে আমি প্রতিক্রিয়া জানাতে খোলা!)

এটি সরল বোর্ন শেল (sh) এর জন্য কাজ করা কঠিন হতে পারে তবে আমি চেষ্টা করিনি ... আমি UN খুব বেশি পছন্দ করি UN :)

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

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

%% 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 

আমার আগের উত্তরটি প্রায় 1/4 স্পেসে ঠিক একই জিনিসটি করেছে :) এটি বেশ বেসিক শেল স্ক্রিপ্টিং এবং গিট রেপোর জন্য উপযুক্ত নয়।
ডেভ

1

ম্যাক অসম্পূর্ণতার চারপাশে কাজ করার জন্য, আমি সামনে এলাম

echo `php -r "echo realpath('foo');"`

দুর্দান্ত নয় তবে ক্রস ওএস


3
পাইথন ২.6++ পিএইচপি এর চেয়ে বেশি প্রান্ত-ব্যবহারকারী সিস্টেমে উপলব্ধ, তাই python -c "from os import path; print(path.realpath('${SYMLINK_PATH}'));"সম্ভবত আরও বোধগম্য হবে। তবুও, আপনাকে শেল স্ক্রিপ্ট থেকে পাইথনটি ব্যবহার করার সময়, আপনি সম্ভবত পাইথন ব্যবহার করা উচিত এবং ক্রস প্ল্যাটফর্ম শেল স্ক্রিপ্টিংয়ের মাথা ব্যাথা নিজেকে বাঁচাতে হবে।
জোনাথন বাল্ডউইন 21

Sh বিল্ট-ইন রিডলিংক, dirname এবং বেস নাম ছাড়া আপনার আর কোনও প্রয়োজন নেই need
ডেভ

@ ডেভ: dirname,, basenameএবং readlinkবহিরাগত ইউটিলিটিগুলি , শেল বিল্ট-ইনগুলি নয়; dirnameএবং basenamePOSIX এর অংশ, readlinkনা।
mklement0

@ mklement0 - আপনি বেশ ঠিক বলেছেন। এগুলি CoreUtils বা সমতুল্য দ্বারা সরবরাহ করা হয়। সকাল 1 টার পরে আমার এসও যাওয়া উচিত নয়। আমার মন্তব্যের সারমর্মটি হ'ল পিএইচপি বা বেস সিস্টেমের মধ্যে ইনস্টল করা এর বাইরে অন্য কোনও ভাষা অনুবাদকের প্রয়োজন নেই। আমি এই পৃষ্ঠায় প্রদত্ত স্ক্রিপ্টটি 1997 এর পর থেকে প্রতিটি লিনাক্স ভেরিয়েন্টে এবং 2006 সাল থেকে ম্যাকোস এক্সকে ত্রুটি ছাড়াই ব্যবহার করেছি। ওপিতে পসিক্স সমাধানের জন্য জিজ্ঞাসা করা হয়নি। তাদের নির্দিষ্ট পরিবেশটি ছিল ম্যাক ওএস এক্স।
ডেভ

@ ডেভ: হ্যাঁ, স্টক ইউটিলিটিগুলি দিয়ে এটি করা সম্ভব, তবে এটি করাও কঠিন (আপনার স্ক্রিপ্টের ত্রুটিগুলি প্রমাণ করে)। তাহলে OS X এর সত্যিই ফোকাস হয় তাহলে এই উত্তরটি হল অনেক সহজ এবং - - যে দেওয়া পুরোপুরি জরিমানা php, অপারেটিং সিস্টেম এক্স দিয়ে আসে তবে যদিও শরীর প্রশ্ন উল্লেখ OS X এর, এটা যেমন যেমন বাঁধা নয়, এবং এটা স্পষ্ট হয়ে যে বিভিন্ন প্ল্যাটফর্মের লোকেরা এখানে উত্তরগুলির জন্য আসে, সুতরাং প্ল্যাটফর্ম-নির্দিষ্ট / নন-পসিক্স কী তা নির্দেশ করা মূল্যবান।
mklement0

1

এটি বাশের একটি সিমলিংক রেজোলভার যা লিঙ্কটি ডিরেক্টরি বা অ ডিরেক্টরি নয় কিনা তা কাজ করে:

function readlinks {(
  set -o errexit -o nounset
  declare n=0 limit=1024 link="$1"

  # If it's a directory, just skip all this.
  if cd "$link" 2>/dev/null
  then
    pwd -P
    return 0
  fi

  # Resolve until we are out of links (or recurse too deep).
  while [[ -L $link ]] && [[ $n -lt $limit ]]
  do
    cd "$(dirname -- "$link")"
    n=$((n + 1))
    link="$(readlink -- "${link##*/}")"
  done
  cd "$(dirname -- "$link")"

  if [[ $n -ge $limit ]]
  then
    echo "Recursion limit ($limit) exceeded." >&2
    return 2
  fi

  printf '%s/%s\n' "$(pwd -P)" "${link##*/}"
)}

নোট করুন যে সমস্ত cd এবং setস্টাফ একটি সাব-শেলের মধ্যে স্থান নেয়।


আসলে, () এর আশেপাশের unnecessary অপ্রয়োজনীয়, যেহেতু () একটি compound like এর মতো একটি "যৌগিক কমান্ড" হিসাবে গণ্য} তবে আপনার এখনও ফাংশন নামের পরে () দরকার।
ক্রিস কগডন

@ ক্রিসকগডন যদি ফাংশনটির নামের পিছনে না থাকে তবে {}চারপাশে ()অপ্রয়োজনীয় নয় ()। বাশ ছাড়াই ফাংশন ঘোষণাগুলি গ্রহণ করে ()কারণ শেলের ঘোষণায় প্যারামিটারের তালিকা থাকে না এবং ()ফাংশন ঘোষণার সাথে কল দেয় না যাতে ()প্রচুর অর্থ হয় না।
solidsnack

0

বর্তমানে আমি যে উত্তরটি আমার পক্ষে ভালভাবে কাজ করছে সেটার একটি ক্রস-প্ল্যাটফর্ম (লিনাক্স এবং ম্যাকস অন্তত) সমাধান হিসাবে আমি এখানে উপস্থাপন করছি।

crosspath()
{
    local ref="$1"
    if [ -x "$(which realpath)" ]; then
        path="$(realpath "$ref")"
    else
        path="$(readlink -f "$ref" 2> /dev/null)"
        if [ $? -gt 0 ]; then
            if [ -x "$(which readlink)" ]; then
                if [ ! -z "$(readlink "$ref")" ]; then
                    ref="$(readlink "$ref")"
                fi
            else
                echo "realpath and readlink not available. The following may not be the final path." 1>&2
            fi
            if [ -d "$ref" ]; then
                path="$(cd "$ref"; pwd -P)"
            else
                path="$(cd $(dirname "$ref"); pwd -P)/$(basename "$ref")"
            fi
        fi
    fi
    echo "$path"
}

এখানে একটি ম্যাকোস (কেবল?) সমাধান রয়েছে। সম্ভবত মূল প্রশ্নের সাথে আরও উপযুক্ত।

mac_realpath()
{
    local ref="$1"
    if [[ ! -z "$(readlink "$ref")" ]]; then
        ref="$(readlink "$1")"
    fi
    if [[ -d "$ref" ]]; then
        echo "$(cd "$ref"; pwd -P)"
    else
        echo "$(cd $(dirname "$ref"); pwd -P)/$(basename "$ref")"
    fi
}

0

আমার উত্তর এখানে বাশ: একটি সিমিলিংকের আসল পথ কীভাবে পাবেন?

স্ক্রিপ্টগুলিতে সংক্ষেপে খুব সহজ:

script_home=$( dirname $(realpath "$0") )
echo Original script home: $script_home

এগুলি জিএনইউ কোর্টিলগুলির অংশ, লিনাক্স সিস্টেমগুলিতে ব্যবহারের জন্য উপযুক্ত।

সমস্ত কিছুর পরীক্ষা করার জন্য, আমরা সিমলিংকটি / home / test2 / এ রেখেছি, কিছু অতিরিক্ত জিনিস সংশোধন করে এবং রুট ডিরেক্টরি থেকে চালনা / কল করব:

/$ /home/test2/symlink
/home/test
Original script home: /home/test

কোথায়

Original script is: /home/test/realscript.sh
Called script is: /home/test2/symlink

0

পিডব্লিউডি ব্যবহার না করা যেতে পারে (উদাহরণস্বরূপ ভিন্ন অবস্থান থেকে কোনও স্ক্রিপ্ট কল করা), রিয়েলপ্যাথ (ডায়ারনাম সহ বা ছাড়াই) ব্যবহার করুন:

$(dirname $(realpath $PATH_TO_BE_RESOLVED))

(একাধিক) সিমলিংক (গুলি) এর মাধ্যমে কল করার সময় বা কোনও অবস্থান থেকে সরাসরি স্ক্রিপ্ট কল করার সময় উভয়ই কাজ করে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.