প্রতীকী লিঙ্ক পুনরাবৃত্তি - এটি "রিসেট" করে তোলে?


64

আমি যখন একই ডিরেক্টরিতে নির্দেশ করে এমন একটি প্রতীকী লিঙ্ক অনুসরণ করি তখন কী হয় তা দেখতে আমি একটু বাশ স্ক্রিপ্ট লিখেছিলাম। আমি এটি প্রত্যাশা করছিলাম হয় হয় খুব দীর্ঘ কাজের ডিরেক্টরি তৈরি করা হবে, বা ক্রাশ হবে। তবে ফলাফল আমাকে অবাক করেছে ...

mkdir a
cd a

ln -s ./. a

for i in `seq 1 1000`
do
  cd a
  pwd
done

কিছু আউটপুট হয়

${HOME}/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a
${HOME}/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a
${HOME}/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a
${HOME}/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a
${HOME}/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a
${HOME}/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a
${HOME}/a
${HOME}/a/a
${HOME}/a/a/a
${HOME}/a/a/a/a
${HOME}/a/a/a/a/a
${HOME}/a/a/a/a/a/a
${HOME}/a/a/a/a/a/a/a
${HOME}/a/a/a/a/a/a/a/a

এখানে কি হচ্ছে?

উত্তর:


88

প্যাট্রিস তার উত্তরে সমস্যার উত্স চিহ্নিত করে , তবে সেখান থেকে কেন আপনি কীভাবে তা পেতে পারেন তা যদি আপনি জানতে চান তবে এখানে দীর্ঘ গল্পটি রয়েছে।

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

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

বর্তমান কার্যনির্বাহী ডিরেক্টরিটির পথ পেতে, একটি প্রক্রিয়া যা করতে হবে তা কেবল হাঁটতে হবে ( নীচে নীচে একটি মূল দেখতে একটি গাছ দেখতে ভাল লাগলে ) গাছটি মূলটিতে ফিরে যাবে, নোডের নামগুলি সন্ধান করবে পথে.

উদাহরণস্বরূপ, একটি প্রক্রিয়া এটির বর্তমান ডিরেক্টরিটি আবিষ্কার করার চেষ্টা /a/b/cকরে ..ডিরেক্টরিটি খুলবে (আপেক্ষিক পথ, ..বর্তমান ডিরেক্টরিতে এন্ট্রিটিও) এবং একই ইনড নম্বর সহ টাইপ ডিরেক্টরি ফাইলের সন্ধান করবে ., এটি সন্ধান করুন cমিলছে, তারপরে খোলা হবে ../..এবং এটি খুঁজে পাওয়া পর্যন্ত /। এখানে কোনও অস্পষ্টতা নেই।

যে কি getwd()বা getcwd()সি ফাংশন কি অথবা অন্তত করতে ব্যবহৃত।

আধুনিক লিনাক্সের মতো কিছু সিস্টেমে, সিস্টেমের কল রয়েছে যে বর্তমান ডিরেক্টরিতে ক্যানোনিকাল পাথ ফিরিয়ে আনবে যা কার্নেল স্পেসে অনুসন্ধান করে (এবং আপনার বর্তমান ডিরেক্টরিটি সন্ধান করার অনুমতি দেয় এমনকি এর সমস্ত উপাদানগুলির অ্যাক্সেস না থাকলেও) , এবং এটি getcwd()সেখানে কল করে। আধুনিক লিনাক্সে, আপনি রিডলিংক () অন করে বর্তমান ডিরেক্টরিতে যাওয়ার পথটিও সন্ধান করতে পারেন /proc/self/cwd

সর্বাধিক ভাষা এবং প্রারম্ভিক শেলগুলি বর্তমান ডিরেক্টরিটিতে পাথ ফেরানোর সময় এটি করে do

আপনার ক্ষেত্রে, আপনি কল করতে পারেন cd aহতে পারে হিসাবে বার হিসাবে আপনি চান, কারণ এটি একটি সিমবলিক লিঙ্ক আছে, .বর্তমান ডিরেক্টরির পরিবর্তন করে না, যাতে সব getcwd(), pwd -P, python -c 'import os; print os.getcwd()', perl -MPOSIX -le 'print getcwd'আপনার ফিরে আসবে ${HOME}

এখন, সিমলিংকগুলি সমস্ত জটিল করে তুলেছে।

symlinksডিরেক্টরি গাছের মধ্যে লাফ দেওয়ার অনুমতি দিন। ইন /a/b/c, /aবা /a/bবা /a/b/cএকটি সিমিলিংক হয়, তবে এর ক্যানোনিকাল পথটি /a/b/cসম্পূর্ণ আলাদা would বিশেষত, ..প্রবেশ /a/b/cঅবশ্যই অগত্যা নয় /a/b

বোর্ন শেলটিতে, যদি আপনি এটি করেন:

cd /a/b/c
cd ..

অথবা এমনকি:

cd /a/b/c/..

আপনার শেষ পর্যন্ত কোনও গ্যারান্টি নেই /a/b

যেমন:

vi /a/b/c/../d

অগত্যা হিসাবে একই হয় না:

vi /a/b/d

kshকোনও একরকম কাজ করার জন্য একটি লজিকাল কারেন্ট ওয়ার্কিং ডিরেক্টরিের একটি ধারণা চালু করে। লোকেরা এটির অভ্যস্ত হয়ে পড়েছিল এবং পসিক্স সেই আচরণটি নির্দিষ্ট করে শেষ করেছিল যার অর্থ আজকাল বেশিরভাগ শাঁস এটিও করে:

জন্য cdএবং pwdbuiltin কমান্ড ( এবং শুধুমাত্র তাদের জন্য (যদিও এছাড়াও popd/ pushdশাঁস তাদের) আছে দিকে), শেল সাম্প্রতিক কাজ করা সংগ্রহের নিজস্ব ধারণা বজায় রাখে। এটি $PWDবিশেষ ভেরিয়েবলে সঞ্চিত ।

যখন তুমি কর:

cd c/d

এমনকি যদি cবা c/d, symlinks হয় যখন $PWDcontaines /a/b, এটা appends c/dশেষ তাই $PWDহয়ে /a/b/c/d। এবং আপনি যখন করবেন:

cd ../e

পরিবর্তে না করে chdir("../e"), এটা করে chdir("/a/b/c/e")

এবং pwdকমান্ডটি কেবল $PWDভেরিয়েবলের বিষয়বস্তু প্রদান করে ।

এটি ইন্টারেক্টিভ শেলগুলিতে দরকারী কারণ pwdআপনি যেভাবে সেখানে এসেছেন সে সম্পর্কে তথ্য দেয় এমন বর্তমান ডিরেক্টরিতে একটি পথ খুঁজে বের করে এবং যতক্ষণ না আপনি কেবল অন্য কমান্ডের ..পক্ষে যুক্তি হিসাবে ব্যবহার করেন ততক্ষণ cdআপনি অবাক হওয়ার সম্ভাবনা কম থাকে, কারণ cd a; cd ..বা cd a/..সাধারণত আপনাকে ফিরে পাবেন আপনি যেখানে ছিলেন

$PWDআপনি যদি না করেন তবে এখন, সংশোধিত হবে না cd। পরের বার আপনি কল করার আগে cdবা pwdঅনেক কিছু ঘটতে পারে, এর যে কোনও উপাদানটির $PWDনাম পরিবর্তন করা যেতে পারে। বর্তমান ডিরেক্টরিটি কখনই পরিবর্তিত হয় না (এটি সর্বদা একই ইনোড, যদিও এটি মোছা হতে পারে) তবে ডিরেক্টরি ট্রিতে এর পথটি পুরোপুরি পরিবর্তন হতে পারে। getcwd()ডিরেক্টরি গাছের নীচে হাঁটার মাধ্যমে প্রতিবার যখন ডাইরেক্টরিটি ডাকা হয় ততক্ষণ তা তথ্যের তথ্য সর্বদা নির্ভুল হয় তবে পসিক্স শেলগুলি দ্বারা প্রয়োগ করা লজিক্যাল ডিরেক্টরিতে, তথ্যটি $PWDবাসি হয়ে যেতে পারে। তাই দৌড়ানোর সময় cdবা pwd, কিছু শেল তার বিরুদ্ধে রক্ষা করতে চাইতে পারে।

সেই বিশেষ পরিস্থিতিতে আপনি বিভিন্ন শেল সহ বিভিন্ন আচরণ দেখেন।

কেউ কেউ ksh93সমস্যাটিকে সম্পূর্ণ উপেক্ষা করতে পছন্দ করে, তাই আপনি কল করার পরেও ভুল তথ্য ফিরে আসবে cd(এবং আপনি সেখানে যে আচরণটি দেখছেন তা আপনি দেখতে পাবেন না bash)।

কিছু পছন্দ করে bashবা zshচেক করে যে $PWDএটি বর্তমান ডিরেক্টরিতে এখনও একটি পথ cd, তবে তা নয় pwd

pdksh উভয় উপর পরীক্ষা করে pwdএবং cd(কিন্তু উপরে pwdআপডেট নেই $PWD)

ash(অন্তত একটি ডেবিয়ান পাওয়া) পরীক্ষা নয়, এবং আপনি কি cd a, এটি একটি প্রকৃত করে cd "$PWD/a", তাই যদি বর্তমান ডিরেক্টরী পরিবর্তিত হয়েছে এবং $PWDবর্তমান ডিরেক্টরির আর পয়েন্ট, এটা আসলে পরিবর্তন করা হবে না aডিরেক্টরির বর্তমান ডিরেক্টরির মধ্যে , তবে একটিতে $PWD(এবং এটি উপস্থিত না থাকলে একটি ত্রুটি ফিরিয়ে দিন)।

আপনি যদি এটির সাথে খেলতে চান তবে আপনি এটি করতে পারেন:

cd
mkdir -p a/b
cd a
pwd
mv ~/a ~/b 
pwd
echo "$PWD"
cd b
pwd; echo "$PWD"; pwd -P # (and notice the bug in ksh93)

বিভিন্ন শেল মধ্যে।

আপনার ক্ষেত্রে, আপনি ব্যবহার করছেন থেকে bash, একটি পর cd a, bashচেক যে $PWDএখনও বর্তমান ডিরেক্টরী স্থানটিকে চিহ্নিত করে। এটি করার stat()জন্য এটি $PWDএর ইনোড নম্বরটি পরীক্ষা করার মানটির সাথে এটির তুলনা করে .

তবে যখন $PWDপথটি সন্ধান করতে অনেকগুলি সিমলিংকগুলি সমাধান করা জড়িত থাকে যা stat()কোনও ত্রুটির সাথে ফিরে আসে, তাই শেলটি $PWDএখনও বর্তমান ডিরেক্টরিটির সাথে সামঞ্জস্য কিনা তা পরীক্ষা করতে পারে না , সুতরাং এটি আবার এটির সাথে গণনা করে getcwd()এবং $PWDতদনুসারে আপডেট হয়।

এখন, প্যাট্রিসের উত্তরটি স্পষ্ট করার জন্য, কোনও সন্ধানের সময় সিমলিংকের সংখ্যার যে পরীক্ষার মুখোমুখি হয়েছিল তা হ'ল সিমলিংক লুপগুলি থেকে রক্ষা করা। সবচেয়ে সহজ লুপটি দিয়ে তৈরি করা যায়

rm -f a b
ln -s a b
ln -s b a

সেই নিরাপদ প্রহরী ব্যতীত cd a/x, সিস্টেমে কোন aলিঙ্ক রয়েছে, এটি সন্ধান করতে হবে bএবং এটি একটি সিমলিংক যা লিঙ্ক করেছে aএবং এটি অনির্দিষ্টকালের জন্য চলে। এর বিরুদ্ধে সতর্ক থাকার সহজ উপায় হ'ল স্বেচ্ছাসেবীর সংখ্যার চেয়ে বেশি সংখ্যক সমাধানের পরে সমাধান করা।

লজিকাল বর্তমান ওয়ার্কিং ডিরেক্টরিতে ফিরে যান এবং কেন এটি কোনও বৈশিষ্ট্য এত ভাল নয়। এটি উপলব্ধি করা গুরুত্বপূর্ণ যে এটি কেবল cdশেলের জন্য এবং অন্যান্য কমান্ডের জন্য নয়।

এই ক্ষেত্রে:

cd -- "$dir" &&  vi -- "$file"

সর্বদা হিসাবে একই হয় না:

vi -- "$dir/$file"

এ কারণেই আপনি মাঝে মাঝে দেখতে পাবেন যে লোকেরা সর্বদা cd -Pবিভ্রান্তি এড়াতে স্ক্রিপ্টগুলিতে ব্যবহার করার পরামর্শ দেয় (আপনি চাইবেন না যে আপনার সফ্টওয়্যার ../xঅন্য কমান্ডের চেয়ে অন্য কোনও যুক্তি হ'ল এটি অন্য ভাষার পরিবর্তে শেলের মধ্যে লেখা হয়েছে)।

-Pবিকল্প অক্ষম হয় লজিক্যাল ডিরেক্টরির হ্যান্ডলিং তাই cd -P -- "$var"আসলে কল নেই chdir()সামগ্রীর উপর $var(-setup যখন $varহয় -কিন্তু যে অন্য গল্প)। এবং এর পরে cd -P, $PWDএকটি ক্যানোনিকাল পাথ থাকবে।


7
মিষ্টি যীশু! এই জাতীয় একটি উত্তরের জন্য ধন্যবাদ, এটি সত্যিই বেশ আকর্ষণীয় :)
লুকাশ

দুর্দান্ত উত্তর, অনেক অনেক ধন্যবাদ! আমার মনে হচ্ছে আমি কিন্ডা এই সমস্ত জিনিস জানতাম তবে আমি কীভাবে বুঝতে পারিনি বা সেগুলি কীভাবে একত্রিত হয়েছিল সে সম্পর্কে ভাবিনি। দুর্দান্ত ব্যাখ্যা।
dimo414

42

এটি লিনাক্স কার্নেল উত্সের একটি হার্ড-কোডেড সীমাবদ্ধতার ফলাফল; অস্বীকার অফ সেবা প্রতিরোধ, নেস্টেড symlinks সংখ্যার উপর সীমা 40 (পাওয়া যায় follow_link()ফাংশন ভিতরে fs/namei.c, ডাকা nested_symlink()কার্নেল সোর্সে)।

আপনি সম্ভবত অন্যান্য কার্নেলগুলি সিমলিংক সমর্থন করে একই রকম আচরণ (এবং সম্ভবত 40 এর চেয়ে আরও একটি সীমা) পেতে পারেন।


1
এটি বন্ধ করার চেয়ে "রিসেট" করার কোনও কারণ আছে কি? অর্থাত x%40বদলে max(x,40)। আমার ধারণা আপনি এখনও ডিরেক্টরিটি বদলে দেখতে পারেন।
লুকাস

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