স্ক্রিপ্টের পরম পাথের পোর্টেবল উপায়?


29

কোন (zsh) স্ক্রিপ্টের পরম পথ নির্ধারণের জন্য পোর্টেবল উপায় কী?

লিনাক্সে আমি এরকম কিছু ব্যবহার করি

mypath=$(readlink -f $0)

... তবে এটি বহনযোগ্য নয়। (উদাহরণস্বরূপ, readlinkডারউইন -fপতাকাটি চিনতে পারে না এবং এর কোনও সমতুল্যও নেই।) (এছাড়াও, এটির readlinkজন্য ব্যবহার করা স্বীকারও করা যায় যে এটি একটি সুন্দর অস্পষ্ট চেহারা হ্যাক))

এর থেকে বেশি বহনযোগ্য উপায় কী?


উত্তর:


28

সাথে zsh, এটি ঠিক:

mypath=$0:A

এখন অন্যান্য শেলগুলির জন্য, যদিও realpath()এবং readlink()এটি স্ট্যান্ডার্ড ফাংশনগুলি (পরবর্তীকালে একটি সিস্টেম কল হচ্ছে), realpathএবং readlinkস্ট্যান্ডার্ড কমান্ড নয় যদিও কিছু সিস্টেমে এক বা অন্য বা উভয় বিভিন্ন আচরণ এবং বৈশিষ্ট্য সেট রয়েছে।

প্রায়শই, বহনযোগ্যতার জন্য, আপনি অবলম্বন করতে চাইতে পারেন perl:

abs_path() {
  perl -MCwd -le '
    for (@ARGV) {
      if ($p = Cwd::abs_path $_) {
        print $p;
      } else {
        warn "abs_path: $_: $!\n";
        $ret = 1;
      }
    }
    exit $ret' "$@"
}

এটি জিএনইউর (জিএনইউ ) এর readlink -fচেয়ে আরও বেশি আচরণ করবে যেহেতু এটির অভিযোগ নেই যে যতক্ষণ ফাইলটির ডায়ারনেম না থাকে ততক্ষণ উপস্থিত না থাকে।realpath()readlink -e


দ্রষ্টব্য: এটি আপনার পক্ষে কাজ করে না .zshrc: পরিবর্তে এই পোস্টটি দেখুন ।
ব্রাইস গিন্টা

24

Zsh এ আপনি নিম্নলিখিতগুলি করতে পারেন:

mypath=${0:a}

অথবা, স্ক্রিপ্টটি যে ডিরেক্টরিতে থাকে সেই ডিরেক্টরিটি পেতে:

mydir=${0:a:h}

উত্স: zshexpn (1) ম্যান পৃষ্ঠা, বিভাগের ইতিহাস বিস্তৃতি, উপধারা সংশোধক (অথবা সহজভাবে info -f zsh -n Modifiers)।


খুব সুন্দর! আমি যুগ যুগ ধরে এই জাতীয় কিছু অনুসন্ধান করেছি এবং এটির জন্য অনুসন্ধান করা জ্যাশ ম্যানাপেজগুলি পুরো গোছাটি পড়েছি, তবে 'ইতিহাসের সম্প্রসারণের' নিচে দেখার জন্য আমার কাছে এমনটি কখনও ঘটেনি।
ভুকার টিমনারাক্রুল

1
GNU এর সমতুল্য readlink -fবরং হবে $0:A
স্টাফেন চ্যাজেলাস

11

আমি বেশ কয়েক বছর ধরে এটি ব্যবহার করছি:

# The absolute, canonical ( no ".." ) path to this script
canonical=$(cd -P -- "$(dirname -- "$0")" && printf '%s\n' "$(pwd -P)/$(basename -- "$0")")

1
আমি এটা পছন্দ করি! এখনও পর্যন্ত, এটি বেশ বহনযোগ্য। উইন্ডোজ ২০০৮ এ সোলারিস, ওমনিওস, লিনাক্স, ম্যাক, এমনকি সাইগউইন-এ কাজ করে
টিম কেনেডি

4
readlink -fস্ক্রিপ্ট নিজেই যখন একটি সিমিলিংক হয় এটি জিএনইউ'র সমতুল্য নয় ।
স্টাফেন চেজেলাস

উবুন্টুতে 16.04 এর সাথে zsh, আমি যদি আমার ঘরের দির ( /home/ville) এ থাকাকালীন এটি সরাসরি বা সাবশেলের (প্রস্তাবিত হিসাবে) সম্পাদন করি তবে এটি মুদ্রণ করে /home/ville/zsh
ভিল

8

এই সিনট্যাক্স (সাথে পরীক্ষিত কোন বোর্ন শেল শৈলী অনুবাদক করতে পোর্টেবল হওয়া উচিত bash, ksh88, ksh93, zsh, mksh, dashএবং busybox sh):

mypath=$(exec 2>/dev/null;cd -- $(dirname "$0"); unset PWD; /usr/bin/pwd || /bin/pwd || pwd)
echo mypath=$mypath

এই সংস্করণটি লেগ্যাসি এটিএন্ডটি বর্ন শেল (নন পসিক্স) এর সাথে সামঞ্জস্যতা যুক্ত করেছে:

mypath=`dirname "$0"`
mypath=`exec 2>/dev/null;(cd -- "$mypath") && cd -- "$mypath"|| cd "$mypath"; unset PWD; /usr/bin/pwd || /bin/pwd || pwd`
echo mypath=$mypath

ধন্যবাদ। তবে, আমি মনে করি আনসেট $PWDকরা অতিরিক্ত ওভারকিল হতে পারে - আপনি কেবল একে একে পরম কারেন্টের মতো সেট করতে পারেন cd -P .। আমি সন্দেহ করি যে এটি বোর্নেশলে কাজ করবে - তবে আপনি প্রথমে যা পরীক্ষা করেছেন তাদের সবার মধ্যে এটি কাজ করা উচিত। আমার জন্য যাই হোক না কেন।
মাইকজার্ভ

আপনি কি ওএস চালাচ্ছেন?
jlliagre

মজ কে? কি?
মাইক্রজারভ

@ মাইকজার মুজ এমন একজন পথচারী যিনি কোনও সমস্যা নিয়ে একটি মন্তব্য পোস্ট করেছিলেন zshএবং dirnameদ্রুত তার / তার মন্তব্য প্রত্যাহার করেন ...
জেলিগ্রে

আপনার বোর্ন শেল স্ক্রিপ্টটি বোর্ন শেলের সাথে কাজ করবে না কারণ বোর্ন শেল সিডি (1) এর জন্য getopt () ব্যবহার করে না।
সুন্দরভাবে

4

ধরে নিচ্ছি আপনার সত্যিকার অর্থে নিখুঁত পাথ বোঝানো হয়েছে, অর্থাৎ মূল ডিরেক্টরি থেকে প্রাপ্ত একটি পথ:

case $0 in
  /*) mypath=$0;;
  *) mypath=$PWD/$0;;
esac

এটি কোনও বোর্ন-স্টাইলের শেলটিতে কাজ করে in

আপনি যদি সমস্ত প্রতীকী লিঙ্কগুলির সমাধানের পথটি বোঝাতে চেয়েছিলেন তবে এটি আলাদা বিষয়। readlink -fলিনাক্সে (কিছু স্ট্রিপড ডাউন বুসিবক্স সিস্টেম বাদে), ফ্রিবিএসডি, নেটবিএসডি, ওপেনবিএসডি এবং সাইগউইনে কাজ করে তবে ওএস / এক্স, এআইএক্স, এইচপি / ইউএক্স বা সোলারিসে নয়। আপনার যদি থাকে তবে আপনি readlinkএটিকে একটি লুপে কল করতে পারেন:

realpath () {
  [ -e "$1" ] || return
  case $1 in
    /*) :;;
    *) set "$PWD/$1";;
  esac
  while [ -L "$1" ]; do
    set "${1%/*}" "$(readlink "$1")"
    case $2 in
      /*) set "$2";;
      *) if [ -z "$1" ]; then set "/$2"; else set "$(cd "$1" && pwd -P)/$2"; fi;;
    esac
  done
  case $1 in
    */.|*/..) set "$(cd "$1" && pwd -P)";;
    */./*|*/../*) set "$(cd "${1%/*}" && pwd -P)/${1##*/}"
  esac
  realpath=$1
}

আপনার যদি না থাকে তবে আপনি readlinkএটির সাথে আনুমানিক আনতে ls -nপারেন, তবে এটি কেবল তখনই কাজ করে যদি lsফাইলের নামের কোনও প্রিন্টযোগ্য অক্ষরকে ম্যাঙ্গেল না করে।

poor_mans_readlink () {
  if [ -L "$1" ]; then
    set -- "$1" "$(LC_ALL=C command ls -n -- "$2"; echo z)"
    set -- "${2%??}"
    set -- "${2#*"$1 -> "}"
  fi
  printf '%s\n' "$1"
}

(অতিরিক্ত zহিসাবে লিংকের লক্ষ্যটি একটি নতুন লাইনে শেষ হয়, যা কমান্ড প্রতিস্থাপন অন্যথায় খেয়ে ফেলবে The realpathফাংশনটি ডিরেক্টরি নামের ক্ষেত্রে এই মামলাটি পরিচালনা করে না।)


1
আউটপুট টার্মিনালে না গেলে lsএমন কোনও প্রয়োগের কথা জানেন যা মুদ্রণহীন অক্ষরগুলিকে মঙ্গল করে।
স্টাফেন চ্যাজেলাস

1
@ স্টাফেনচাজেলাস touch Stéphane; LC_ALL=C busybox ls Stéphane | catSt??phane(এটি যদি নামটি ইউটিএফ -8 এ থাকে তবে লাতিন 1 আপনাকে একক দেয় ?)। আমি মনে করি আমি এটি পুরানো বাণিজ্যিক ইউনিটগুলিতেও দেখেছি।
গিলস 'তাই খারাপ হওয়া বন্ধ করুন'

@ স্টাফেনচাজেলাস আমি বেশ কয়েকটি বাগ স্থির করেছি তবে ব্যাপকভাবে পরীক্ষা করা হয়নি। যদি তা এখনও কিছু ক্ষেত্রে ব্যর্থ হয় তবে আমাকে জানান (কিছু ডিরেক্টরিতে মৃত্যুদণ্ডের অনুমতিের অভাব ব্যতীত, আমি edge প্রান্তের ক্ষেত্রে মোকাবিলা করব না)।
গিলস 'অসন্তুষ্ট হওয়া বন্ধ করুন'

@ গিলস - এটি কি busybox? গিট অনুসারে busybox ls২০১১ সাল থেকে একটি কোড পরিবর্তন হয়নি My আমার busybox ls- সার্কো 2013 - এই জিনিসটি করে না। এই এক - প্রায় 2012 - নাএটি কারণ ব্যাখ্যা করতে পারে। আপনি কি busyboxইউনিকোড সমর্থন দিয়ে তৈরি করেছেন - wchar সমর্থন অন্তর্ভুক্ত করতে? আপনি হয়ত এটিকে যেতে চাইতে পারেন, অন্যথায় mkinitcpio busyboxপ্যাকেজের বিল্ড বিকল্পগুলি পরীক্ষা করতে ।
মাইকসার্ভ

গিলস - আমি বিশ্বাস করি আমি প্রাথমিকভাবে এই উত্তরটি - বা কমপক্ষে এর একটি অংশকে ভুল বুঝেছি। যদিও আমি দৃ mang়ভাবে বিশ্বাস করি যে আপনার ম্যাংলিং ফাইলের নামগুলি মন্ত্রকে সম্পূর্ণ ভ্রান্তি বলে মনে হচ্ছে, অবশ্যই আপনার দরিদ্র_মানস_প্রেডলিঙ্কটি খুব ভালভাবে সম্পন্ন হয়েছে। আপনি যদি আমাকে সম্পাদনা করার দয়া করেন - যে কোনও সম্পাদনা করবে - এবং আমাকে পিংগিংয়ের পরে, আমার এই বিষয়ে আমার ভোটটি উল্টাতে পছন্দ করা উচিত।
মাইকজার্ভ

1

তবে শর্ত থাকে আপনি বর্তমান ডিরেক্টরির অনুমতি চালানো আছে - অথবা ডাইরেক্টরি যার থেকে আপনি আপনার শেল স্ক্রিপ্ট মৃত্যুদন্ড কার্যকর উপর - আপনি একটি ডিরেক্টরি আপনার প্রয়োজন হয় একটি সুনির্দিষ্ট পাথ চান cd

দশকের দশম ধাপ cdspec

তাহলে -Pবিকল্প কার্যকরী হলে, $PWDএনভায়রনমেন্ট ভেরিয়েবল স্ট্রিং, যাতে দ্বারা আউটপুট হবে সেট হইবে pwd -P। যদি বর্তমান ডিরেক্টরিটি নির্ধারণ করতে নতুন ডিরেক্টরিতে বা সেই ডিরেক্টরিটির কোনও অভিভাবকের কাছে পর্যাপ্ত অনুমতি না থাকে তবে $PWDপরিবেশের ভেরিয়েবলের মান অনির্দিষ্ট।

এবং তারপরে pwd -P

স্ট্যান্ডার্ড আউটপুটে লিখিত পথের নামটিতে এমন কোনও উপাদান থাকবে না যা টাইপ প্রতীকী লিঙ্কের ফাইলগুলি উল্লেখ করে। যদি pwdইউটিলিটি স্ট্যান্ডার্ড আউটপুটে লিখতে পারে এমন একাধিক পাথের নাম রয়েছে , যেখানে একটি একক / স্ল্যাশ অক্ষর দিয়ে শুরু হয় এবং দুটি বা স্ল্যাশ অক্ষর দিয়ে এক বা একাধিক শুরু হয়, তবে এটি একক / স্ল্যাশ অক্ষর দিয়ে পথের নাম লিখতে হবে। পথের নামটিতে নেতৃস্থানীয় এক বা দুটি / স্ল্যাশ অক্ষরের পরে কোনও অপ্রয়োজনীয় / স্ল্যাশ অক্ষর থাকবে না।

এর কারণ cd -Pহ'ল বর্তমান কার্যনির্বাহী ডিরেক্টরিটি সেট করতে হবে যা pwd -Pঅন্যথায় প্রিন্ট করা উচিত এবং যা নিম্নলিখিত কাজ cd -করে $OLDPWDতা মুদ্রণ করতে হবে :

mkdir ./dir
ln -s ./dir ./ln
cd ./ln ; cd . ; cd -

আউটপুট

/home/mikeserv/test/ln

এটার জন্য অপেক্ষা কর...

cd -P . ; cd . ; cd -

আউটপুট

/home/mikeserv/test/dir

এবং যখন আমি মুদ্রণ cd -করছি সাথে মুদ্রণ $OLDPWD। যত তাড়াতাড়ি আমি এখন একটি নিখুঁত পথ হিসাবে cdসেট করে - তাই আমার অন্য কোনও ভেরিয়েবলের প্রয়োজন নেই don't এবং প্রকৃতপক্ষে, আমার এমনকি ট্রেলিংয়ের প্রয়োজন হবে না তবে অসাবধান অবস্থায় যখন একটি ইন্টারেক্টিভ শেলটিতে পুনরায় সেট করার নির্দিষ্ট আচরণ রয়েছে । সুতরাং এটি বিকাশ করার জন্য কেবল একটি ভাল অভ্যাস।$PWDcd -P . $PWD/.$PWD$HOMEcd

সুতরাং পথে উপরেরটি করা কেবলমাত্র তার পাথটি ${0%/*}যাচাই করার জন্য পর্যাপ্ত পরিমাণের বেশি হওয়া উচিত $0, তবে $0দুর্ভাগ্যক্রমে আপনি সম্ভবত এটির ডিরেক্টরি পরিবর্তন করতে পারবেন না।

এখানে একটি ফাংশন যা এটি পরিচালনা করবে:

zpath() { cd -P . || return
    _out() { printf "%s$_zdlm\n" "$PWD/${1##*/}"; }
    _cd()  { cd -P "$1" ; } >/dev/null 2>&1
    while [ $# -gt 0 ] && _cd .
    do  if     _cd "$1" 
        then   _out
        elif ! [ -L "$1" ] && [ -e "$1" ] 
        then   _cd "${1%/*}"; _out "$1"
        elif   [ -L "$1" ]
        then   ( while set -- "${1%?/}"; _cd "${1%/*}"; [ -L "${1##*/}" ]
                 do    set " $1" "$(_cd -; ls -nd -- "$1"; echo /)"
                       set -- "${2#*"$1" -> }"
                 done; _out "$1" 
    );  else   ( PS4=ERR:\ NO_SUCH_PATH; set -x; : "$1" )
    fi; _cd -; shift; done
    unset -f _out _cd; unset -v _zdlm                                    
}

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

যুক্তিযুক্ত বা যুক্ত ছাড়া বলা হয় এটি প্রথমে $PWDতার সাধারণ মানটিতে পুনরায় সেট করা হয় - এটি সেখানে প্রয়োজনীয় যে কোনও লিঙ্ককে তাদের লক্ষ্যগুলিতে সমাধান করে। যুক্তি ছাড়াই কল করা এবং এটি সম্পর্কে; তবে তাদের সাথে আহ্বান জানানো হয়েছে এবং এটি প্রতিটিের জন্য পথটিকে সমাধান এবং ক্যানোনিকালাইজড করবে বা অন্যথায় stderrকেন একটি বার্তা প্রিন্ট করবে ।

কারণ এটি বেশিরভাগ বর্তমান শেলটিতে কাজ করে এটি কোনও দৈর্ঘ্যের একটি আর্গুমেন্ট তালিকা পরিচালনা করতে সক্ষম হওয়া উচিত। এটি $_zdlmভেরিয়েবলটিও সন্ধান করে (এটি unsetযখন এটি হয় তখন এটিও ঘটে) এবং এর সি-পালানো মানটি তত্ক্ষণাত্ তার প্রতিটি আর্গুমেন্টের ডানদিকে মুদ্রণ করে, যার প্রত্যেকটি সর্বদা একক \nইওলাইন অক্ষর দ্বারা অনুসরণ করা হয় ।

এটি অনেকগুলি ডিরেক্টরি পরিবর্তন করে, তবে এটির মূল নীতিতে সেট করা ব্যতীত, এটি প্রভাব ফেলবে না $PWD, যদিও $OLDPWDএটি কোনওভাবেই গণনা করা যায় না it

এটি এর প্রতিটি আর্গুমেন্ট যত তাড়াতাড়ি সম্ভব ত্যাগ করার চেষ্টা করে। এটি প্রথমে প্রবেশ করার চেষ্টা cdকরে $1। এটি যদি এটি করতে পারে তবে তর্কটির প্রমিত পথটি মুদ্রণ করে stdout। এটি যদি তা না পারে তবে এটি $1উপস্থিত রয়েছে এবং এটি কোনও নরম লিঙ্ক নয় soft সত্য হলে এটি মুদ্রণ করে।

এই পদ্ধতিতে এটি কোনও ফাইল টাইপের আর্গুমেন্ট পরিচালনা করে যা শেলকে অনুমতি দেওয়ার অনুমতি দেয় যদি না $1কোনও প্রতীকী লিঙ্ক থাকে যা কোনও ডিরেক্টরিতে নির্দেশ করে না। whileসেক্ষেত্রে এটি একটি সাব-শেলের মধ্যে লুপকে কল করে ।

এটি lsলিঙ্কটি পড়তে কল করে। কোনও ডিরেক্টরিকে নির্ভরযোগ্যতার সাথে পরিচালনা করতে বর্তমান ডিরেক্টরিটি প্রথমে তার প্রাথমিক মানতে অবশ্যই পরিবর্তন করা উচিত এবং তাই, কমান্ড সাবস্টিটিউশন সাবশেলের মাধ্যমে ফাংশনটি করে:

cd -...ls...echo /

lsলিঙ্কটির নাম এবং স্ট্রিংটি সম্পূর্ণরূপে অন্তর্ভুক্ত করতে এটির আউটপুট বাম থেকে সামান্য কম ->। আমি প্রথমে এটিটি এড়াতে চেষ্টা করেছি shiftএবং $IFSএটি প্রমাণিত হয়েছে যে এটি সবচেয়ে নির্ভরযোগ্য পদ্ধতিটি যতটা কাছাকাছি আমি চিত্রিত করতে পারি। গিলসের দরিদ্র_মানস_প্রেডলিঙ্কটি একই কাজ করে - এবং এটি খুব ভালভাবে সম্পন্ন হয়েছে।

ফাইল প্রক্রিয়াটি lsঅবশ্যই কোনও নরম লিঙ্ক না হওয়া পর্যন্ত এটি এই প্রক্রিয়াটিকে একটি লুপে পুনরাবৃত্তি করবে । এই মুহুর্তে এটি সেই প্রান্তটিকে পূর্বের মতো cdপ্রিন্টের সাথে পূর্বের মতো করে on

ব্যবহারের উদাহরণ:

zpath \
    /tmp/script \   #symlink to $HOME/test/dir/script.sh
    ln \            #symlink to ./dir/
    ln/nl \         #symlink to ../..
    /dev/fd/0 \     #currently a here-document like : dash <<\HD
    /dev/fd/1 \     #(zlink) | dash
    file \          #regular file                                             
    doesntexist \   #doesnt exist
    /dev/disk/by-path/pci-0000:00:16.2-usb-0:3:1.0-scsi-0:0:0:0 \
    /dev/./././././././null \
    . ..      

আউটপুট

/home/mikeserv/test/dir/script.sh
/home/mikeserv/test/dir/
/home/mikeserv/test/
/tmp/zshtpKRVx (deleted)
/proc/17420/fd/pipe:[1782312]
/home/mikeserv/test/file
ERR: NO_SUCH_PATH: doesntexist
/dev/sdd
/dev/null
/home/mikeserv/test/
/home/mikeserv/

বা সম্ভবত ...

ls
dir/  file  file?  folder/  link@  ln@  script*  script3@  script4@

zdlm=\\0 zpath * | cat -A

আউটপুট

/home/mikeserv/test/dir/^@$               
/home/mikeserv/test/file^@$
/home/mikeserv/test/file$
^@$
/home/mikeserv/test/folder/^@$
/home/mikeserv/test/file$               #'link' -> 'file\n'
^@$
/home/mikeserv/test/dir/^@$             #'ln' -> './dir'
/home/mikeserv/test/script^@$
/home/mikeserv/test/dir/script.sh^@$    #'script3' -> './dir/script.sh'
/home/mikeserv/test/dir/script.sh^@$    #'script4' -> '/tmp/script' -> ...

0

অ্যালগরিদমের নতুন সংজ্ঞা দেওয়া থেকে বাধা দেওয়ার জন্য পাইথন পাওয়া গেলে সহানুভূতিশীল ওয়ান-লাইনারের কী হবে?

function readlink { python -c "import os.path; print os.path.realpath('$1')"; }

একই হিসাবে https://stackoverflow.com/a/7305217

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