"পুনঃনির্দেশ" এবং "পাইপ" এর মধ্যে পার্থক্য কী?


204

এই প্রশ্নটি কিছুটা বোকা লাগতে পারে তবে আমি পুনর্নির্দেশ এবং পাইপের মধ্যে পার্থক্যটি দেখতে পাচ্ছি না।

পুনঃনির্দেশটি স্টাডাউট / স্টিডিন / স্ট্ডার পুনঃনির্দেশের জন্য ব্যবহৃত হয়, যেমন ls > log.txt

পাইপগুলি একটি কমান্ডের আউটপুট অন্য কমান্ডের ইনপুট হিসাবে দিতে ব্যবহৃত হয়, যেমন ls | grep file.txt

তবে কেন একই জিনিসটির জন্য দুটি অপারেটর রয়েছে?

কেন কেবল ls > grepআউটপুটটি পাস করার জন্য লিখবেন না , এটি কি কেবল এক ধরণের পুননির্দেশনাও নয়? আমি কী মিস করছি?

উত্তর:


223

পাইপ অন্য প্রোগ্রাম বা ইউটিলিটি আউটপুট পাস করতে ব্যবহৃত হয় ।

পুনর্নির্দেশ কোনও ফাইল বা প্রবাহকে আউটপুট পাস করতে ব্যবহৃত হয় ।

উদাহরণ: thing1 > thing2বনামthing1 | thing2

thing1 > thing2

  1. আপনার শেল নামক প্রোগ্রামটি চালাবে thing1
  2. ফলাফল যা thing1বলা হয় সেগুলি ডাকা একটি ফাইলে স্থাপন করা হবে thing2। (দ্রষ্টব্য - যদি thing2বিদ্যমান থাকে তবে এটি ওভাররাইট করা হবে)

আপনি যদি প্রোগ্রাম থেকে আউটপুটটি thing1কোনও প্রোগ্রামে পাস করতে চান তবে আপনি thing2নিম্নলিখিতটি করতে পারেন:

thing1 > temp_file && thing2 < temp_file

যা হবে

  1. প্রোগ্রাম চালানো thing1
  2. নামের একটি ফাইলের মধ্যে আউটপুট সংরক্ষণ করুন temp_file
  3. প্রোগ্রাম চালিত নাম চালানো thing2, ভান করে যে কীবোর্ডে থাকা ব্যক্তিটি temp_fileইনপুট হিসাবে লিখিত সামগ্রীগুলি টাইপ করে ।

যাইহোক, এটি আঠালো, তাই তারা এটি করার সহজ উপায় হিসাবে পাইপ তৈরি করেছিল। thing1 | thing2হিসাবে একই জিনিস নাthing1 > temp_file && thing2 < temp_file

মন্তব্যে প্রশ্নের আরও বিশদ সরবরাহ করতে সম্পাদনা:

যদি >"প্রোগ্রামে পাস" এবং "ফাইলটিতে লিখুন" উভয়ই হওয়ার চেষ্টা করা হয়, তবে এটি উভয় দিক থেকেই সমস্যা তৈরি করতে পারে।

প্রথম উদাহরণ: আপনি কোনও ফাইলে লেখার চেষ্টা করছেন। ইতিমধ্যে সেই নামের একটি ফাইল রয়েছে যা আপনি ওভাররাইট করতে চান। তবে ফাইলটি কার্যকর হয় ut সম্ভবত, এটি ইনপুটটি পাস করে এই ফাইলটি কার্যকর করার চেষ্টা করবে। আপনাকে নতুন ফাইলনামে আউটপুট লিখার মতো কিছু করতে হবে, তারপরে ফাইলটির নাম পরিবর্তন করুন।

দ্বিতীয় উদাহরণ: ফ্লোরিয়ান ডিয়েশ উল্লেখ করেছেন যে, একই নামের সিস্টেমে অন্য কোনও কমান্ড থাকলে (তা কার্যকর করার পথে) কী হবে? যদি আপনি নিজের বর্তমান ফোল্ডারে সেই নামটি দিয়ে কোনও ফাইল তৈরি করার পরিকল্পনা করেন তবে আপনি আটকে যাবেন।

তৃতীয়ত: আপনি যদি কোনও কমান্ড ভুল টাইপ করেন তবে এটি আপনাকে সতর্ক করে না যে কমান্ডটি বিদ্যমান নেই। এই মুহুর্তে, আপনি ls | gerp log.txtএটি টাইপ করলে তা আপনাকে জানাবে bash: gerp: command not found। যদি >উভয়ই বোঝানো হয় তবে এটি কেবল আপনার জন্য একটি নতুন ফাইল তৈরি করবে (তারপরে সতর্ক করুন যে এটি কী করতে হবে তা জানে না log.txt)।


ধন্যবাদ. আপনি thing1 > temp_file && thing2 < temp_fileপাইপগুলির সাহায্যে আরও সহজ করার কথা উল্লেখ করেছেন। তবে কেন >অপারেটরটিকে এটি করতে পুনরায় ব্যবহার করবেন না, যেমন thing1 > thing2কমান্ডের জন্য thing1এবং thing2? অতিরিক্ত অপারেটর কেন |?
জন থ্রিপউড

1
"আউটপুট নিন এবং এটি একটি ফাইলে লিখুন" "আউটপুট নিন এবং এটি একটি আলাদা প্রোগ্রামে দিন" এর চেয়ে আলাদা একটি ক্রিয়া। আমি আমার উত্তরে আরও চিন্তাভাবনাগুলি সম্পাদনা করব ...
ডেভিড ওনিল

1
@ জন থ্রিপউডের তাদের আলাদা অর্থ রয়েছে। lessউদাহরণস্বরূপ, যদি আমি নামের কোনও ফাইলে কিছু পুনর্নির্দেশ করতে চাই ? thing | lessএবং thing > lessএকেবারে পৃথক, যেমন তারা বিভিন্ন জিনিস করে। আপনি যা প্রস্তাব করবেন তা দ্বিধাদ্বন্দ্ব তৈরি করবে।
দারখোগ

"জিনিস 1> টেম্প_ফায়াল" কেবল "জিনিস 1 | টি টেম্প ফাইলে" এর জন্য সিনট্যাকটিক চিনি কিনা তা বলা কি সঠিক? টি সম্পর্কে সন্ধান করার পর থেকে আমি কখনই পুনঃনির্দেশগুলি ব্যবহার করি না।
শ্রীধর সারনোবাত

2
@ শ্রীধর-সারনোবাত নং, teeআদেশটি কিছু আলাদা করে। teeস্ক্রিন ( stdout) এবং ফাইল উভয় আউটপুট লিখুন। পুনর্নির্দেশ শুধুমাত্র ফাইলটি করে।
ডেভিড ওনিল

22

পুনঃনির্দেশটি ব্যবহার করে আরও শক্ত এবং আরও ত্রুটি হওয়ার সম্ভাবনা foo > barরয়েছে এমন নামের একটি কমান্ড রয়েছে কিনা তার অর্থ যদি নির্ভর করে bar: প্রতিবার আমি কোনও ফাইলে পুনঃনির্দেশ করতে চাইলে প্রথমে আমার গন্তব্য ফাইলের মতো কোনও কমান্ড আছে কিনা তা পরীক্ষা করে দেখতে হয়েছিল।


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

13

ইউনিক্স এবং লিনাক্স সিস্টেম অ্যাডমিনিস্ট্রেশন হ্যান্ডবুক থেকে:

ফেরৎ

শেলটি </>> এবং >> চিহ্নগুলিকে একটি কমান্ডের ইনপুট বা ফাইল থেকে বা আউটপুট পুনরায় তৈরি করার নির্দেশাবলী হিসাবে ব্যাখ্যা করে ।

পাইপ

একটি কমান্ডের STDOUT কে অন্য কমান্ডের STDIN এর সাথে সংযুক্ত করতে। | প্রতীক, সাধারণত পাইপ হিসাবে পরিচিত।

সুতরাং আমার ব্যাখ্যাটি হ'ল: যদি এটি আদেশ করার কমান্ড হয় তবে একটি পাইপ ব্যবহার করুন। আপনি যদি কোনও ফাইল থেকে বা আউটপুট তুলছেন তবে পুনঃনির্দেশটি ব্যবহার করুন।


12

দুটি অপারেটরের মধ্যে একটি গুরুত্বপূর্ণ পার্থক্য রয়েছে:

  1. ls > log.txt -> এই কমান্ডটি log.txt ফাইলে আউটপুট প্রেরণ করে।

  2. ls | grep file.txt-> এই কমান্ডটি পাইপ ( |) ব্যবহারের মাধ্যমে ls এর আউটপুটটিকে গ্রেপ কমান্ডে প্রেরণ করে এবং গ্রেপ কমান্ড পূর্ববর্তী কমান্ড দ্বারা প্রদত্ত ইনপুটটিতে file.txt অনুসন্ধান করে।

প্রথম দৃশ্য ব্যবহার করে যদি আপনাকে একই কাজটি সম্পাদন করতে হয়, তবে তা হবে:

ls > log.txt; grep 'file.txt' log.txt

সুতরাং একটি পাইপ (সহ |) অন্য কমান্ডে আউটপুট প্রেরণে ব্যবহৃত হয়, অন্যদিকে >আউটপুটটিকে কোনও ফাইলে পুনর্নির্দেশ করতে পুনঃনির্দেশ (সহ ) ব্যবহার করা হয়।


3

উভয়ের মধ্যে একটি বড় সিনট্যাকটিক পার্থক্য রয়েছে:

  1. একটি পুনঃনির্দেশিত করা একটি প্রোগ্রামের একটি যুক্তি
  2. একটি পাইপ দুটি কমান্ড পৃথক করে

আপনি ভালো পুনঃনির্দেশ মনে করতে পারেন: cat [<infile] [>outfile]। এটি বোঝায় যে অর্ডারটি কোনও বিষয় নয়: cat <infile >outfileএকই cat >outfile <infile। এমনকি আপনি অন্য যুক্তিগুলির সাথে পুনঃনির্দেশগুলি মেশাতে পারেন: cat >outfile <infile -bএবং cat <infile -b >outfileউভয়ই পুরোপুরি ভাল। এছাড়াও আপনি একসঙ্গে স্ট্রিং একাধিক ইনপুট অথবা আউটপুট (ইনপুট ক্রমানুসারে পড়া করা হবে এবং সব আউটপুট প্রতিটি আউটপুট ফাইল লেখা হবে) করতে পারেন: cat >outfile1 >outfile2 <infile1 <infile2। পুনর্নির্দেশের লক্ষ্য বা উত্স হয় ফাইলের নাম বা কোনও স্ট্রিমের নাম (যেমন & 1 টি কমপক্ষে ব্যাশে) হতে পারে।

তবে পাইপগুলি একটি কমান্ডকে অন্য কমান্ড থেকে সম্পূর্ণ আলাদা করে দেয়, আপনি সেগুলি যুক্তির সাথে মিশতে পারবেন না:

[command1] | [command2]

পাইপ কমান্ড 1 থেকে স্ট্যান্ডার্ড আউটপুটে লিখিত প্রত্যেকটি জিনিস নিয়ে যায় এবং এটি কমান্ড 2 এর স্ট্যান্ডার্ড ইনপুটটিতে প্রেরণ করে।

আপনি পাইপিং এবং পুনঃনির্দেশও একত্রিত করতে পারেন। উদাহরণ স্বরূপ:

cat <infile >outfile | cat <infile2 >outfile2

প্রথমটি catইনফিল থেকে লাইনগুলি পড়বে, তারপরে একই সাথে প্রতিটি লাইন আউটফাইলে লিখবে এবং দ্বিতীয়টিতে প্রেরণ করবে cat

দ্বিতীয়টিতে cat, স্ট্যান্ডার্ড ইনপুট প্রথমে পাইপ (ইনফিলের বিষয়বস্তু) থেকে পড়বে, তারপরে infile2 থেকে পড়বে, প্রতিটি লাইন আউটফাইল 2 তে লিখবে। এটি চালানোর পরে, আউটফাইল ইনফিলের অনুলিপি হবে এবং আউটফাইল 2 ইনফাইলে এর পরে ইনফাইলে থাকবে।

পরিশেষে, আপনি আসলে "এখানে স্ট্রিং" পুনঃনির্দেশ (কেবল বাশ পরিবার) এবং ব্যাকটিক্স ব্যবহার করে আপনার উদাহরণের সাথে সত্যই অনুরূপ কিছু করেন:

grep blah <<<`ls`

হিসাবে একই ফলাফল দেবে

ls | grep blah

তবে আমি মনে করি যে পুনঃনির্দেশ সংস্করণটি প্রথমে ls এর সমস্ত আউটপুট একটি বাফারে (স্মৃতিতে) পড়বে এবং তারপরে সেই বাফারটিকে একবারে এক লাইনে গ্রেপ করে ফিড করবে, যেখানে পাইপযুক্ত সংস্করণটি প্রতিটি লাইনটি এল এর থেকে প্রকাশিত হবে, এবং লাইনটি গ্রেপকে পাস করুন।


1
নিতপিক: পুনর্নির্দেশে অর্ডার সম্পর্কিত বিষয়গুলি আপনি যদি একটি এফডি অন্যকে echo yes 1>&2 2>/tmp/blah; wc -l /tmp/blah; echo yes 2>/tmp/blah 1>&2; wc -l /tmp/blahপুনর্নির্দেশ করেন : আরও, কোনও ফাইলে পুনঃনির্দেশ শুধুমাত্র শেষ পুনঃনির্দেশ ব্যবহার করবে। echo yes >/tmp/blah >/tmp/blah2শুধুমাত্র লিখতে হবে /tmp/blah2
মুরু

2
পুনঃনির্দেশ করা আসলে প্রোগ্রামটির পক্ষে যুক্তি নয়। প্রোগ্রামটি কোথায় আউটপুট যায় (বা ইনপুটটি আসে) তা জানবে না বা যত্ন করবে না। প্রোগ্রাম চালানোর আগে জিনিসগুলি কীভাবে সাজানো যায় তা বাশকে বলার উপায়।
আলয়েস মাহডাল

3

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

টি এল; ডিআর

  • |পাইপগুলি ডিস্কে প্রবেশের সাথে সম্পর্কিত নয়, সুতরাং ডিস্ক ফাইল সিস্টেমের একটি ইনোড সংখ্যা নেই (তবে কার্নেল-স্পেসে পাইপফেস ভার্চুয়াল ফাইল সিস্টেমের ইনোড রয়েছে ), তবে পুনঃনির্দেশগুলি প্রায়শই ফাইলগুলিতে জড়িত থাকে, যার সাথে ডিস্ক এন্ট্রি থাকে এবং যার ফলে সংশ্লিষ্ট হয় inode।
  • পাইপগুলি lseek()সক্ষম হয় না যাতে কমান্ডগুলি কিছু ডেটা পড়তে না পারে এবং তারপরে পুনরায় রিওয়াইন্ড করতে পারে, তবে আপনি যখন পুনঃনির্দেশ করেন >বা <সাধারণত এটি এমন কোনও ফাইল যা lseek()সক্ষম অবজেক্ট, সুতরাং কমান্ডগুলি তারা খুশি তবে নেভিগেট করতে পারে।
  • পুনর্নির্দেশগুলি হ'ল ফাইল বর্ণনাকারীদের ম্যানিপুলেশনস, যা অনেকগুলি হতে পারে; পাইপগুলিতে দুটি ফাইল বর্ণনাকারী রয়েছে - একটি বাম কমান্ডের জন্য এবং একটি ডান কমান্ডের জন্য
  • স্ট্যান্ডার্ড স্ট্রিম এবং পাইপগুলিতে পুনঃনির্দেশ উভয়টি বাফার করা।
  • পাইপ প্রায় সর্বদা কাঁটা জড়িত এবং তাই প্রক্রিয়া জোড়া যুক্ত; পুনর্নির্দেশগুলি - সর্বদা নয়, যদিও উভয় ক্ষেত্রেই ফলস্বরূপ ফাইল বর্ণনকারীগুলি উপ-প্রক্রিয়াগুলির দ্বারা উত্তরাধিকার সূত্রে প্রাপ্ত হয়।
  • পাইপ সবসময় ফাইল বর্ণনাকারী সংযুক্ত করে (একটি জুড়ি), পুনর্নির্দেশগুলি - হয় কোনও পথনাম বা ফাইল বর্ণনাকারী ব্যবহার করে।
  • পাইপগুলি হ'ল আন্ত-প্রক্রিয়া যোগাযোগ পদ্ধতি, অন্যদিকে পুনর্নির্দেশগুলি কেবল খোলা ফাইল বা ফাইল-জাতীয় বস্তুগুলিতে ম্যানিপুলেশন
  • দু'জনেই dup2()ফাইল বর্ণনাকারীর অনুলিপি সরবরাহ করার জন্য হুডের নীচে সিস্টস্কল নিয়োগ করেন , যেখানে প্রকৃত তথ্যের প্রবাহ ঘটে।
  • পুনর্নির্দেশগুলি execবিল্ট-ইন কমান্ডের সাথে "বিশ্বব্যাপী" প্রয়োগ করা যেতে পারে ( এটি এবং এটি দেখুন ), সুতরাং আপনি যদি exec > output.txtপ্রতিটি আদেশ করেন output.txtতবে তা থেকে লিখতে হবে । |পাইপগুলি কেবল বর্তমান কমান্ডের জন্য প্রয়োগ করা হয় (যার অর্থ সরল কমান্ড বা সাবশেলের মতো seq 5 | (head -n1; head -n2)বা যৌগিক কমান্ড)।
  • যখন ফেরৎ ফাইল সম্পন্ন হলে, ভালো জিনিস echo "TEST" > fileএবং echo "TEST" >> fileউভয় ব্যবহার open()এটি ফাইলের প্রাপ্ত syscall ( তাও দেখতে ) এবং এটি পাস করার তা থেকে ফাইল বর্ণনাকারী পেতে dup2()। পাইপগুলি |কেবল ব্যবহার pipe()এবং dup2()সিস্কেল।

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

ভূমিকা

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

পুনঃনির্দেশ এবং পাইপগুলির উত্স

ডেনিস রিচের প্রবন্ধটি ভবিষ্যদ্বাণীমূলক পেট্রোগ্লাইফস অনুসারে পাইপগুলির উৎপত্তি ম্যালকম ডগলাস ম্যাকিল্রয়ের 1964 সালের অভ্যন্তরীণ মেমো থেকে হয়েছিল , যখন তারা মাল্টিক্স অপারেটিং সিস্টেমের সাথে কাজ করছিলেন । উক্তি:

আমার শক্তিশালী উদ্বেগকে সংক্ষেপে জানাতে:

  1. আমাদের বাগানের পায়ের পাতার মোজাবিশেষের মতো প্রোগ্রামগুলি সংযুক্ত করার কিছু উপায় থাকতে হবে - যখন অন্য উপায়ে ডেটা ম্যাসেজ করার প্রয়োজন হয় তখন এটি হয়ে যায় অন্য বিভাগে স্ক্রু। এটিও আইওয়ের পথ।

যা স্পষ্ট তা হ'ল সেই সময়ে প্রোগ্রামগুলি ডিস্কে লিখতে সক্ষম ছিল, তবে আউটপুট বড় হলে এটি অদক্ষ ছিল। ইউনিক্স পাইপলাইন ভিডিওতে ব্রায়ান কার্নিগানের ব্যাখ্যাটি উদ্ধৃত করতে :

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

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

আরও গভীরতর হচ্ছে: শেলটির সিস্কেল এবং অভ্যন্তরীণ কাজ

আমরা ফাইল বর্ণনাকারীর ধারণা দিয়ে শুরু করি । ফাইল বর্ণনাকারীরা মূলত একটি উন্মুক্ত ফাইল (এটি ডিস্কের একটি ফাইল, বা মেমরির, বা বেনামে ফাইল) এর বর্ণনা দেয় যা কোনও পূর্ণসংখ্যার সংখ্যা দ্বারা উপস্থাপিত হয়। দুটি স্ট্যান্ডার্ড ডেটা স্ট্রিম (স্টিডিন, স্টডআউট, স্টেডার) যথাক্রমে ফাইল বর্ণনাকারী 0,1 এবং 2। ওরা কোথা থেকে আসে ? ভাল, শেল কমান্ডগুলিতে ফাইল বর্ণনাকারী তাদের পিতামাতাদের - শেল থেকে উত্তরাধিকার সূত্রে প্রাপ্ত হয়। এবং এটি সমস্ত প্রক্রিয়াগুলির জন্য সাধারণভাবে সত্য - শিশু প্রক্রিয়া পিতামাতার ফাইল বর্ণনাকারীদের উত্তরাধিকার সূত্রে পায়। ডেমনগুলির জন্য সমস্ত উত্তরাধিকার সূত্রে প্রাপ্ত ফাইল বর্ণনাকারী বন্ধ করে এবং / অথবা অন্য জায়গায় পুনর্নির্দেশ করা সাধারণ।

পুনঃনির্দেশে ফিরে যান। আসলেই কি? এটি এমন একটি প্রক্রিয়া যা শেলকে কমান্ডের জন্য ফাইল বর্ণনাকারী প্রস্তুত করতে বলে (কারণ কমান্ড চালুর আগে শেল দ্বারা পুনর্নির্দেশগুলি সম্পন্ন করা হয়), এবং ব্যবহারকারীর পরামর্শ অনুসারে সেগুলি নির্দেশ করুন। স্ট্যান্ডার্ড ডেফিনেশনে আউটপুট ফেরৎ হয়

[n]>word

যে [n]ফাইল বর্ণনাকারী নম্বর আছে। আপনি যখন echo "Something" > /dev/null1 নম্বরটি করেন তখন সেখানে জড়িত থাকে এবং echo 2> /dev/null

হুডের নীচে এটি dup2()সিস্টেম কলের মাধ্যমে ফাইল বর্ণনাকারীর সদৃশ করে করা হয় । চলুন df > /dev/null। শেলটি একটি শিশু প্রক্রিয়া তৈরি করবে যেখানে এটি dfচালিত হবে, তবে এর আগে এটি /dev/nullফাইল বর্ণনাকারী # 3 হিসাবে খুলবে এবং dup2(3,1)জারি করা হবে, যা ফাইল বিবরণকারী 3 এর একটি অনুলিপি তৈরি করে এবং অনুলিপিটি হবে 1 আপনি কীভাবে আপনার দুটি ফাইল আছে তা জানেন file1.txtএবং file2.txt, এবং যখন cp file1.txt file2.txtআপনার কাছে দুটি একই ফাইল থাকবে তবে আপনি সেগুলি স্বাধীনভাবে পরিচালনা করতে পারেন? কিন্ডা এখানে একই ঘটনা ঘটছে। প্রায়শই আপনি দেখতে পারেন যে নির্বাচনে দাঁড়ানোর আগে bashকি করতে হবে dup(1,10)একটি কপি ফাইল বর্ণনাকারী # 1 যা করতে stdout(এবং যে কপি FD # 10 হবে) যাতে এটা পরে পুনরুদ্ধার হবে। গুরুত্বপূর্ণ হ'ল নোট করা যখন আপনি বিল্ট-ইন কমান্ডগুলি বিবেচনা করেন(যা নিজেই শেলের অংশ, এবং কোনও /binবা অন্য কোথাও কোনও ফাইল নেই ) বা অ-ইন্টারেক্টিভ শেলের সাধারণ কমান্ড , শেলটি শিশু প্রক্রিয়া তৈরি করে না।

এবং তারপর আমরা ভালো জিনিস আছে [n]>&[m]এবং [n]&<[m]। এটি ফাইল বর্ণনাকারীর সদৃশ, যা dup2()এখনকার শেল সিনট্যাক্সের মতো একই প্রক্রিয়াটি ব্যবহারকারীর জন্য সুবিধাজনকভাবে উপলব্ধ।

পুনঃনির্দেশ সম্পর্কে নোট করার জন্য একটি গুরুত্বপূর্ণ বিষয় হ'ল তাদের অর্ডার স্থির নয়, তবে শেল কীভাবে ব্যবহারকারী চায় তার ব্যাখ্যা কীভাবে তা গুরুত্বপূর্ণ। নিম্নলিখিত তুলনা করুন:

# Make copy of where fd 2 points , then redirect fd 2
$ ls -l /proc/self/fd/  3>&2  2> /dev/null
total 0
lrwx------ 1 user user 64 Sep 13 00:08 0 -> /dev/pts/0
lrwx------ 1 user user 64 Sep 13 00:08 1 -> /dev/pts/0
l-wx------ 1 user user 64 Sep 13 00:08 2 -> /dev/null
lrwx------ 1 runner user 64 Sep 13 00:08 3 -> /dev/pts/0
lr-x------ 1 user user 64 Sep 13 00:08 4 -> /proc/29/fd

# redirect fd #2 first, then clone it
$ ls -l /proc/self/fd/    2> /dev/null 3>&2
total 0
lrwx------ 1 user user 64 Sep 13 00:08 0 -> /dev/pts/0
lrwx------ 1 user user 64 Sep 13 00:08 1 -> /dev/pts/0
l-wx------ 1 user user 64 Sep 13 00:08 2 -> /dev/null
l-wx------ 1 user user 64 Sep 13 00:08 3 -> /dev/null
lr-x------ 1 user user 64 Sep 13 00:08 4 -> /proc/31/fd

শেল স্ক্রিপ্টিং এগুলির ব্যবহারিক ব্যবহার বহুমুখী হতে পারে:

এবং আরও অনেকে.

সঙ্গে নদীর গভীরতানির্ণয় pipe()এবংdup2()

সুতরাং পাইপগুলি কীভাবে তৈরি হয়? pipe()সিস্কেল মাধ্যমে , যা ইনপুট হিসাবে pipefdদুটি ধরণের আইটেম int(পূর্ণসংখ্যার) নামক একটি অ্যারে (ওরফে তালিকা) হিসাবে গ্রহণ করবে । এই দুটি পূর্ণসংখ্যা ফাইল বর্ণনাকারী। pipefd[0]পাইপের পড়া শেষ হতে পারে এবং pipefd[1]লেখার শেষ হবে। সুতরাং df | grep 'foo', এর grepঅনুলিপি পাবেন pipefd[0]এবং এর dfএকটি অনুলিপি পাবেন pipefd[1]। কিন্তু কিভাবে ? অবশ্যই, dup2()সিস্কেলের যাদু দিয়ে । জন্য dfআমাদের উদাহরণে, এর কথা বলা যাক pipefd[1]# 4 আছে, তাই শেল একটি শিশু করতে, কি করতে হবে dup2(4,1)(আমার স্মরণ cpউদাহরণ?), এবং তারপর কি execve()আসলে চালানোর জন্য df। স্বাভাবিকভাবে,dfফাইল বর্ণনাকারী # 1 উত্তরাধিকার সূত্রে প্রাপ্ত হবে, তবে এটি অজানা হবে যে এটি আর টার্মিনালটির দিকে নির্দেশ করছে না, তবে আসলে এফডি # 4, যা আসলে পাইপের লেখার শেষ end স্বাভাবিকভাবেই, grep 'foo'ফাইল বর্ণনাকারীর বিভিন্ন সংখ্যক ব্যতীত একই জিনিসটি ঘটবে ।

এখন, আকর্ষণীয় প্রশ্ন: আমরা কী এমন পাইপগুলি তৈরি করতে পারি যা এফডি # 2 কেও পুনর্নির্দেশ করতে পারে, কেবল এফডি # 1 নয়? হ্যাঁ, বাস্তবে এটি হ'ল |&বাশে। পসিক্স স্ট্যান্ডার্ডটির জন্য df 2>&1 | grep 'foo'সিনট্যাক্স সমর্থন করার জন্য শেল কমান্ড ভাষা প্রয়োজন , তবে bashএটিও করে |&

গুরুত্বপূর্ণ বিষয়গুলি যা গুরুত্বপূর্ণ তা হ'ল পাইপগুলি সর্বদা ফাইল বর্ণনাকারীদের সাথে ডিল করে। সেখানে বিদ্যমান FIFOবা নামযুক্ত পাইপ রয়েছে , যার ডিস্কে একটি ফাইলের নাম রয়েছে এবং আসুন আপনি এটি ফাইল হিসাবে ব্যবহার করুন তবে পাইপের মতো আচরণ করে। তবে |পাইপের ধরণগুলি হ'ল অজ্ঞাতনামা পাইপ হিসাবে পরিচিত - তাদের কোনও ফাইলের নাম নেই, কারণ তারা সত্যিকার অর্থে কেবল দুটি বস্তু এক সাথে সংযুক্ত। আমরা ফাইলগুলির সাথে কাজ করছি না এই বিষয়টিও একটি গুরুত্বপূর্ণ জড়িত: পাইপগুলি lseek()সক্ষম নয়। মেমরি বা ডিস্কে থাকা ফাইলগুলি স্থিতিশীল - প্রোগ্রামগুলি lseek()120 বাইটে লাফিয়ে সিস্কল ব্যবহার করতে পারে , তারপরে 10 বাইটে ফিরে, তারপরে শেষের দিকে এগিয়ে যেতে পারে। পাইপ স্থিতিশীল নয় - সেগুলি ক্রমযুক্ত এবং তাই আপনি তাদের কাছ থেকে প্রাপ্ত ডেটা রিওয়াইন্ড করতে পারবেন নাlseek()। কিছু ফাইল প্রোগ্রাম থেকে যদি তারা ফাইল বা পাইপ থেকে পড়ছেন তবে এটি দক্ষতার সাথে দক্ষতার জন্য প্রয়োজনীয় সামঞ্জস্য করতে পারে; অন্য কথায়, একটি progযদি আমি না সনাক্ত করতে cat file.txt | progবা prog < input.txt। এর বাস্তব কাজের উদাহরণ লেজ

পাইপগুলির অন্য দুটি অত্যন্ত আকর্ষণীয় সম্পত্তি হ'ল তাদের একটি বাফার রয়েছে, যা লিনাক্সে 4096 বাইট এবং লিনাক্স উত্স কোডে সংজ্ঞায়িত হিসাবে তাদের আসলে একটি ফাইল সিস্টেম রয়েছে ! এগুলি চারপাশের ডেটা পাস করার জন্য কেবল কোনও বস্তু নয়, তারা নিজেরাই একটি ডেটাস্ট্রাকচার! বাস্তবে পাইপস ফাইল সিস্টেম বিদ্যমান রয়েছে, যা পাইপ এবং এফআইএফও উভয়ই পরিচালনা করে, পাইপগুলির নিজ নিজ ফাইল সিস্টেমে একটি ইনোড নম্বর থাকে:

# Stdout of ls is wired to pipe
$ ls -l /proc/self/fd/  | cat  
lrwx------ 1 user user 64 Sep 13 00:02 0 -> /dev/pts/0
l-wx------ 1 user user 64 Sep 13 00:02 1 -> pipe:[15655630]
lrwx------ 1 user user 64 Sep 13 00:02 2 -> /dev/pts/0
lr-x------ 1 user user 64 Sep 13 00:02 3 -> /proc/22/fd
# stdin of ls is wired to pipe
$ true | ls -l /proc/self/fd/0
lr-x------ 1 user user 64 Sep 13 03:58 /proc/self/fd/0 -> 'pipe:[54741]'

লিনাক্স পাইপগুলি পুনঃনির্দেশের মতোই ইউনি-দিকনির্দেশক। কিছু ইউনিক্স-এর মতো বাস্তবায়নের ক্ষেত্রে - দ্বি-দিকনির্দেশক পাইপ রয়েছে। যদিও শেল স্ক্রিপ্টিংয়ের যাদু দিয়ে, আপনি লিনাক্সে দ্বি-দিকনির্দেশক পাইপও তৈরি করতে পারেন ।

আরো দেখুন:


2

অন্যান্য উত্তরগুলিতে যুক্ত করতে, সূক্ষ্ম অর্থ সংক্রান্ত পার্থক্যও রয়েছে - যেমন পাইপগুলি পুনঃনির্দেশের চেয়ে আরও সহজেই বন্ধ হয়:

seq 5 | (head -n1; head -n1)                # just 1
seq 5 > tmp5; (head -n1; head -n1) < tmp5   # 1 and 2
seq 5 | (read LINE; echo $LINE; head -n1)   # 1 and 2

প্রথম উদাহরণে, যখন প্রথম কলটি headশেষ হয়, এটি পাইপটি বন্ধ করে এবং seqসমাপ্ত হয়, তাই দ্বিতীয়টির জন্য কোনও ইনপুট উপলব্ধ নেই head

দ্বিতীয় উদাহরণে, মাথাটি প্রথম লাইনটি গ্রাস করে, তবে এটি নিজের stdin পাইপটি বন্ধ করলে ফাইলটি পরবর্তী কলটি ব্যবহারের জন্য উন্মুক্ত থাকে।

তৃতীয় উদাহরণটি দেখায় যে আমরা যদি readপাইপটি বন্ধ করা এড়াতে ব্যবহার করি তবে এটি সাবপ্রসেসের মধ্যে এখনও উপলব্ধ।

সুতরাং "স্ট্রিম" হ'ল জিনিসটি আমরা স্ট্যান্ডিন ইত্যাদির মাধ্যমে ডেটা এড়িয়ে চলি এবং উভয় ক্ষেত্রেই একই, তবে পাইপটি দুটি প্রক্রিয়া থেকে প্রবাহকে সংযুক্ত করে, যেখানে একটি পুনর্নির্দেশ প্রক্রিয়া এবং একটি ফাইলের মধ্যে একটি প্রবাহকে সংযুক্ত করে, তাই আপনি উভয় মিল এবং পার্থক্য উত্স দেখতে পারেন।

পিএস যদি আপনি যতটা আগ্রহী হন এবং / বা আমি যেমন ছিল সেগুলি দ্বারা বিস্মিত হন, trapতবে প্রক্রিয়াগুলি কীভাবে সমাধান হয় তা দেখতে আপনি আরও খনন করতে পারেন , যেমন:

(trap 'echo seq EXITed >&2' EXIT; seq 5) | (trap 'echo all done' EXIT; (trap 'echo first head exited' EXIT; head -n1)
echo '.'
(trap 'echo second head exited' EXIT; head -n1))

কখনও কখনও প্রথম প্রক্রিয়াটি 1মুদ্রণের আগে বন্ধ হয়ে যায় , কখনও কখনও পরে।

exec <&-পাইপের ব্যবহারের আনুমানিক আচরণ (যদিও ত্রুটি থাকা সত্ত্বেও) আনুমানিকভাবে পুনঃনির্দেশ থেকে স্ট্রিমটি বন্ধ করতে ব্যবহার করা আমার কাছে আকর্ষণীয় মনে হয়েছিল :

seq 5 > tmp5
(trap 'echo all done' EXIT
(trap 'echo first head exited' EXIT; head -n1)
echo '.'
exec <&-
(trap 'echo second head exited' EXIT; head -n1)) < tmp5`

"যখন প্রথম দিকে যাওয়ার প্রথম কলটি শেষ হয়ে যায়, তখন এটি পাইপটি বন্ধ করে দেয়" এটি দুটি কারণেই আসলে ভুল। একটি, (হেড -n1; শিরোনাম -n1) দুটি কমান্ড সহ সাবশেল, যার প্রতিটি উত্তরাধিকার সূত্রে ডেস্ক্রিপ্টর 0 হিসাবে পাইপের শেষ প্রান্তে প্রাপ্ত হয়, এবং সুতরাং সাবশেল এবং প্রতিটি কমান্ডের সেই ফাইল বর্ণনাকারী খোলা থাকে। দ্বিতীয় কারণ, আপনি স্ট্রেস -f বাশ-সি 'সিক 5 দিয়ে দেখতে পারেন (মাথা -n1; মাথা -n1) '' ' সুতরাং প্রথম মাথা কেবল ফাইল বর্ণনাকারীর অনুলিপিটি বন্ধ করে দেয়
সের্গি কলডিয়াজহনি

তৃতীয় উদাহরণটিও সঠিক নয়, কারণ readকেবলমাত্র প্রথম লাইনই (এটি একটি বাইট 1এবং নিউলাইন জন্য) ব্যবহার করে। seqমোট 10 বাইটে প্রেরিত (5 নম্বর এবং 5 টি নতুন লাইন)। সুতরাং পাইপ বাফারে 8 বাইট বাকী রয়েছে এবং সেই কারণেই দ্বিতীয়টি headকাজ করে - পাইপ বাফারে এখনও ডেটা পাওয়া যায়। বিটিডব্লিউ, মাথাটি কেবল তখনই বাইরে আসে যখন 0 বাইট পড়ে, কন্ডা যেমন পড়ছেhead /dev/null
সের্গি কলডিয়াজহনি

স্পষ্টির জন্য ধন্যবাদ। আমি কি সঠিকভাবে বুঝতে পারি যে seq 5 | (head -n1; head -n1)প্রথম কলটিতে পাইপটি খালি হয়ে যায়, তাই এটি এখনও একটি মুক্ত অবস্থায় রয়েছে তবে দ্বিতীয় কলটির কোনও ডেটা নেই head? সুতরাং পাইপ এবং পুনর্নির্দেশের মধ্যে আচরণের মধ্যে পার্থক্য হ'ল মাথাটি পাইপের বাইরে থেকে সমস্ত ডেটা টেনে নেয়, তবে ফাইল হ্যান্ডেল থেকে কেবল 2 টি লাইন?
জুলিয়ান ডি ভাল

এটাই সঠিক. এবং এটি এমন কিছু যা straceআমি প্রথম মন্তব্যে কমান্ড দিয়ে দেখা যেতে পারে । পুনঃনির্দেশের সাথে, টিএমপি ফাইলটি ডিস্কে রয়েছে যা এটি সন্ধানযোগ্য করে তোলে (কারণ তারা সিস্কেল ব্যবহার করে lseek()- কমান্ডগুলি ফাইলটি প্রথম বাইট থেকে শেষের দিকে লাফাতে পারে তবে তারা চায়। কাজ প্রথম সবকিছু পড়া, অথবা যদি ফাইল বড় - মাধ্যমে RAM তা কিছু মানচিত্র mmap()কল আমি একবার আমার নিজের করেনি। tailপাইথন, এবং ঠিক একই সমস্যাতে পড়েছি।
Sergiy Kolodyazhnyy

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

1

আমি আজ সিতে এটিকে নিয়ে একটি সমস্যায় পড়েছি। মূলত পাইপগুলির কাছে পুনঃনির্দেশ করার জন্য বিভিন্ন শব্দার্থক শব্দ রয়েছে, এমনকি পাঠানো হলেও stdin। সত্যিকার অর্থে আমি মনে করি পার্থক্যগুলির ভিত্তিতে পাইপগুলি অন্য কোথাও চলে যাওয়া উচিত stdin, যাতে এটি stdinকল করে stdpipe(একটি স্বেচ্ছাসেবী পার্থক্য করতে) বিভিন্ন উপায়ে পরিচালনা করা যায়।

এই বিবেচনা. যখন একটি প্রোগ্রাম আউটপুট অন্যটিতে পাইপ করা হয় তখন fstatমনে হয় একটি ফাইল রয়েছে তা st_sizeসত্ত্বেও শূন্যটি ফিরে আসে ls -lha /proc/{PID}/fd। যখন একটি ফাইল পুনঃনির্দেশিত এই ক্ষেত্রে (অন্তত ডেবিয়ান নেই wheezy, stretchএবং jessieভ্যানিলা এবং উবুন্টু 14.04, 16.04ভ্যানিলা।

আপনি যদি cat /proc/{PID}/fd/0পুনঃনির্দেশ দিয়ে থাকেন তবে আপনি যতবার চান তার পুনরাবৃত্তি করতে সক্ষম হবেন। আপনি যদি পাইপ দিয়ে এটি করেন তবে আপনি খেয়াল করবেন যে দ্বিতীয়বার আপনি টানা দ্বিতীয়বার টাস্ক চালনা করলে আপনি একই আউটপুট পাবেন না।

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