তারা ইন্টারলিভ করে! আপনি কেবল সংক্ষিপ্ত আউটপুট বিস্ফোরণের চেষ্টা করেছেন, যা আনস্লিট্ট থেকে যায়, তবে বাস্তবে কোনও নির্দিষ্ট আউটপুট আনস্প্লিট থাকার নিশ্চয়তা দেওয়া শক্ত hard
আউটপুট বাফারিং
এটি নির্ভর করে প্রোগ্রামগুলি কীভাবে তাদের আউটপুটকে বাফার করে। Stdio গ্রন্থাগার যে অধিকাংশ প্রোগ্রাম ব্যবহার যখন তারা লেখা ব্যবহারসমূহ বাফার আউটপুট আরো কার্যকর করা। প্রোগ্রাম কোনও ফাইলে লেখার জন্য একটি লাইব্রেরি ফাংশনকে কল করার সাথে সাথে ডেটা আউটপুট দেওয়ার পরিবর্তে ফাংশনটি এই ডেটাটি একটি বাফারে সংরক্ষণ করে এবং বাফারটি পূরণ করার পরে কেবল তথ্যটি আউটপুট করে। এর অর্থ ব্যাচগুলিতে আউটপুট হয়। আরও স্পষ্টভাবে, তিনটি আউটপুট মোড রয়েছে:
- আনফফার্ড: বাফার ব্যবহার না করেই ডেটা অবিলম্বে লেখা হয়। প্রোগ্রামটি যদি আউটপুটটিকে ছোট ছোট টুকরো করে লেখায় তবে এটি ধীর হতে পারে, উদাহরণস্বরূপ অক্ষর অনুসারে। এটি আদর্শ ত্রুটির জন্য ডিফল্ট মোড।
- সম্পূর্ণ বাফার: ডেটা কেবল তখনই লেখা হয় যখন বাফারটি পূর্ণ থাকে। স্টাইডার ব্যতীত কোনও পাইপে বা নিয়মিত ফাইলে লেখার সময় এটি ডিফল্ট মোড।
- লাইন-বাফার করা: প্রতিটি নিউলাইনের পরে ডেটা লেখা হয় বা যখন বাফার পূর্ণ থাকে। স্টারডার ব্যতীত টার্মিনালে লেখার সময় এটি ডিফল্ট মোড।
প্রোগ্রামগুলি প্রতিটি ফাইল আলাদা করে আচরণ করতে পুনরায় প্রোগ্রাম করতে পারে এবং স্পষ্টভাবে বাফারটিকে ফ্লাশ করতে পারে। কোনও প্রোগ্রাম ফাইলটি বন্ধ করে দেয় বা স্বাভাবিকভাবে প্রস্থান করলে বাফারটি স্বয়ংক্রিয়ভাবে ফ্লাশ হয় is
একই পাইপে লিখিত সমস্ত প্রোগ্রাম যদি হয় লাইন-বাফার মোড ব্যবহার করে, বা আনফারড মোড ব্যবহার করে এবং প্রতিটি লাইন একটি আউটপুট ফাংশনে একক কল দিয়ে লিখতে থাকে এবং লাইনগুলি যদি একক অংশে লেখার জন্য যথেষ্ট ছোট হয়, তবে আউটপুটটি সম্পূর্ণ রেখার আন্তঃবিভাজন হবে। তবে যদি কোনও প্রোগ্রাম পুরোপুরি বাফার মোড ব্যবহার করে বা লাইনগুলি দীর্ঘ হয় তবে আপনি মিশ্র লাইন দেখতে পাবেন।
এখানে একটি উদাহরণ যেখানে আমি দুটি প্রোগ্রাম থেকে আউটপুট ইন্টারলিভ করি। আমি লিনাক্সে জিএনইউ কোর্টিল ব্যবহার করেছি; এই ইউটিলিটির বিভিন্ন সংস্করণ আলাদা আচরণ করতে পারে।
yes aaaa
aaaa
লাইন-বাফার মোডের মূলত সমতুল্য যা লিখে চিরকালের জন্য। yes
উপযোগ আসলে একটি সময়ে একাধিক লাইন লিখেছেন, কিন্তু প্রতিটি সময় এটি আউটপুট নির্গত আউটপুট লাইনের একটি পূর্ণ সংখ্যা হয়।
echo bbbb; done | grep b
bbbb
সম্পূর্ণ-বাফার মোডে চিরকালের জন্য লেখেন । এটি 8192 এর বাফার আকার ব্যবহার করে এবং প্রতিটি লাইন 5 বাইট দীর্ঘ long 5 যেহেতু 8192 বিভাজন করে না, তাই লেখকের মধ্যে সীমানা সাধারণত একটি লাইনের সীমানায় হয় না।
আসুন তাদের একসাথে পিচ করা যাক।
$ { yes aaaa & while true; do echo bbbb; done | grep b & } | head -n 999999 | grep -e ab -e ba
bbaaaa
bbbbaaaa
baaaa
bbbaaaa
bbaaaa
bbbaaaa
ab
bbbbaaa
আপনি দেখতে পাচ্ছেন, হ্যাঁ কখনও কখনও গ্রেপ বা বিপরীতভাবে বিঘ্নিত হয়। প্রায় 0.001% লাইনই বাধাগ্রস্ত হয়েছিল, তবে এটি ঘটেছিল। আউটপুটটি এলোমেলোভাবে তৈরি হয়েছে যাতে ব্যাঘাতের সংখ্যা পৃথক হয় তবে আমি প্রতিবার অন্তত কয়েকটি বাধা দেখেছি। বাফার প্রতি লাইনের সংখ্যা হ্রাস হওয়ায় বিঘ্নিত হওয়ার সম্ভাবনা বাড়ার পরে লাইনগুলি দীর্ঘ হলে বাধাপ্রাপ্ত লাইনের একটি উচ্চতর ভগ্নাংশ থাকবে।
আউটপুট বাফারিং সামঞ্জস্য করার বিভিন্ন উপায় রয়েছে । প্রধানগুলি হ'ল:
stdbuf -o0
জিএনইউ কোর্টিলস এবং ফ্রিবিএসডি-তে কিছু অন্যান্য সিস্টেমে পাওয়া প্রোগ্রামের সাথে ডিফল্ট সেটিংস পরিবর্তন না করে স্টেডিও লাইব্রেরি ব্যবহার করে এমন প্রোগ্রামগুলিতে বাফারিং বন্ধ করুন । আপনি বিকল্পভাবে লাইন বাফারিংয়ে স্যুইচ করতে পারেন stdbuf -oL
।
- প্রোগ্রামটির আউটপুট কেবলমাত্র এই উদ্দেশ্যে তৈরি করা টার্মিনালের মাধ্যমে নির্দেশিত করে লাইন বাফারিং-এ স্যুইচ করুন
unbuffer
। কিছু প্রোগ্রাম অন্যান্য উপায়ে অন্যরকম আচরণ করতে পারে, উদাহরণস্বরূপ, grep
যদি এর আউটপুটটি টার্মিনাল হয় তবে ডিফল্টরূপে রঙগুলি ব্যবহার করে।
- প্রোগ্রামটি কনফিগার করুন, উদাহরণস্বরূপ,
--line-buffered
জিএনইউ গ্রেপ পাস করে।
আসুন আবার উপরে স্নিপেটটি দেখুন, এবার উভয় পক্ষের লাইন বাফারিংয়ের সাথে।
{ stdbuf -oL yes aaaa & while true; do echo bbbb; done | grep --line-buffered b & } | head -n 999999 | grep -e ab -e ba
abbbb
abbbb
abbbb
abbbb
abbbb
abbbb
abbbb
abbbb
abbbb
abbbb
abbbb
abbbb
abbbb
সুতরাং এবার হ্যাঁ কখনও গ্রেপ বাধা দেয় না, তবে গ্রেপ কখনও কখনও হ্যাঁতে বাধা দেয়। আমি পরে আসব কেন।
পাইপ ইন্টারলিভিং
যতক্ষণ না প্রতিটি প্রোগ্রাম একবারে একটি লাইন আউটপুট করে এবং লাইনগুলি যথেষ্ট ছোট হয়, আউটপুট লাইনগুলি খুব সুন্দরভাবে পৃথক করা হবে। তবে এটি কাজ করার জন্য লাইনগুলি কত দীর্ঘ হতে পারে তার একটি সীমা রয়েছে। পাইপ নিজেই একটি স্থানান্তর বাফার আছে। যখন কোনও প্রোগ্রাম কোনও পাইপে আউটপুট দেয়, তখন লেখক প্রোগ্রাম থেকে পাইপের ট্রান্সফার বাফারে ডেটা অনুলিপি করা হয় এবং তারপরে পাইপের স্থানান্তর বাফার থেকে পাঠক প্রোগ্রামে স্থানান্তরিত হয়। (কমপক্ষে ধারণাগতভাবে - কার্নেল কখনও কখনও এটি একটি একক অনুলিপিতে অনুকূলিত করতে পারে))
পাইপের ট্রান্সফার বাফারের সাথে ফিট করার চেয়ে কপি করার জন্য যদি আরও বেশি ডেটা থাকে তবে কার্নেলটি একবারে একটি বাফারফুল অনুলিপি করে। যদি একাধিক প্রোগ্রাম একই পাইপে লিখতে থাকে এবং কার্নেল যে প্রথম প্রোগ্রামটি বেছে নিয়েছে তারা একাধিক বাফারফুল লিখতে চায়, তবে গ্যারান্টি নেই যে দ্বিতীয় বার কার্নেল আবার একই প্রোগ্রামটি বেছে নেবে। উদাহরণস্বরূপ, পি যদি বাফার আকার হয়, foo
2 * পি বাইট bar
লিখতে চায় এবং 3 বাইট লিখতে চায়, তবে একটি সম্ভাব্য ইন্টারলিভিং হ'ল পি বাইটস foo
, তারপরে 3 বাইট bar
এবং পি বাইটগুলি থেকে foo
।
আমার সিস্টেমে উপরের হ্যাঁ + গ্রেপের উদাহরণে ফিরে আসার সাথে সাথে yes aaaa
একসাথে 8192-বাইট বাফারের সাথে যতটা পারা যায় তার জন্য অনেকগুলি লাইন লিখতে দেখা যায়। যেহেতু 5 টি বাইট লেখার জন্য রয়েছে (4 টি মুদ্রণযোগ্য অক্ষর এবং নতুন লাইন), এর অর্থ এটি প্রতিবার 8190 বাইট লিখে দেয়। পাইপ বাফার আকার 4096 বাইট। সুতরাং হ্যাঁ থেকে 4096 বাইট পাওয়া সম্ভব, তারপরে গ্রেপ থেকে কিছু আউটপুট, এবং তারপরে বাকী লেখা হ্যাঁ (8190 - 4096 = 4094 বাইট) থেকে পাওয়া যাবে। 4096 বাইটস 819 লাইন aaaa
এবং একাকী জন্য ঘর ছেড়ে দেয় a
। অতএব এই একাকীটির সাথে একটি লাইন a
তারপরে গ্রেপ থেকে একটি লেখার সাথে একটি লাইন দেয় abbbb
।
যদি আপনি কী চলছে তার বিশদটি দেখতে চান, তবে getconf PIPE_BUF .
আপনার সিস্টেমে আপনাকে পাইপ বাফার আকারটি জানিয়ে দেবে এবং প্রতিটি প্রোগ্রামের মাধ্যমে করা সিস্টেম কলগুলির একটি সম্পূর্ণ তালিকা দেখতে পাবেন
strace -s9999 -f -o line_buffered.strace sh -c '{ stdbuf -oL yes aaaa & while true; do echo bbbb; done | grep --line-buffered b & }' | head -n 999999 | grep -e ab -e ba
ক্লিন লাইন ইন্টারলিভিংয়ের গ্যারান্টি কীভাবে দেওয়া যায়
লাইনের দৈর্ঘ্য যদি পাইপ বাফার আকারের চেয়ে ছোট হয় তবে লাইন বাফারিং গ্যারান্টি দেয় যে আউটপুটটিতে কোনও মিশ্র লাইন থাকবে না।
লাইনের দৈর্ঘ্য যদি আরও বড় হতে পারে তবে একাধিক প্রোগ্রাম একই পাইপে লেখার সময় স্বেচ্ছাসেবী মিশ্রণ এড়ানোর কোনও উপায় নেই। বিচ্ছেদ নিশ্চিত করার জন্য, আপনাকে প্রতিটি প্রোগ্রামকে আলাদা পাইপে লিখিত করতে হবে এবং লাইনগুলি একত্রিত করার জন্য একটি প্রোগ্রাম ব্যবহার করতে হবে। উদাহরণস্বরূপ, জিএনইউ সমান্তরাল এটি ডিফল্টরূপে করে।