প্রক্রিয়া প্রতিস্থাপন আউটপুট ক্রম বাইরে


16

দ্য

echo one; echo two > >(cat); echo three; 

কমান্ড অপ্রত্যাশিত আউটপুট দেয়।

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

প্রত্যাশিত আউটপুট:

one
two
three

আসল আউটপুট:

prompt$ echo one; echo two > >(cat); echo three;
one
three
prompt$ two

এছাড়াও, এই দুটি কমান্ডটি আমার দৃষ্টিকোণ থেকে সমতুল্য হওয়া উচিত, তবে তারা তা করে না:

##### first command - the pipe is used.
prompt$ seq 1 5 | cat
1
2
3
4
5
##### second command - the process substitution and redirection are used.
prompt$ seq 1 5 > >(cat)
prompt$ 1
2
3
4
5

আমি কেন মনে করি, তাদের একই হওয়া উচিত? কারণ, উভয়ই অনামী পাইপ - উইকিপিডিয়া, প্রক্রিয়া প্রতিস্থাপনের মাধ্যমে seqআউটপুটটিকে ইনপুটটিতে সংযুক্ত করে ।cat

প্রশ্ন: কেন এটি এভাবে আচরণ করে? আমার ত্রুটি কোথায়? বিস্তৃত উত্তরটি কাঙ্ক্ষিত ( bashএটি হুডের নীচে কী করে তা ব্যাখ্যা সহ) প্রত্যাশিত ।



2
প্রকৃতপক্ষে, আরও ভাল হবে যদি অন্য প্রশ্নটিকে এটির একটি সদৃশ হিসাবে চিহ্নিত করা হয় কারণ এই প্রশ্নটি আরও বেশি। যে কারণে আমি আমার উত্তরটি এখানে অনুলিপি করেছি।
স্টাফেন চেজেলাস

উত্তর:


21

হ্যাঁ, এর bashমতো ksh(যেখানে বৈশিষ্ট্যটি আসে), প্রক্রিয়া প্রতিস্থাপনের অভ্যন্তরের প্রক্রিয়াগুলির জন্য অপেক্ষা করা হয় না (স্ক্রিপ্টে পরবর্তী কমান্ড চালানোর আগে)।

একটি জন্য <(...)এক, সাধারণত জরিমানা যে হিসাবে:

cmd1 <(cmd2)

শেলটির জন্য অপেক্ষা করা থাকবে cmd1এবং cmd1সাধারণত cmd2পাইপটিতে ফাইলের শেষ হওয়া পর্যন্ত এটি পড়ার কারণে অপেক্ষা করা হবে এবং ফাইলটি শেষের দিকে সাধারণত cmd2মারা যায় তখন ঘটে when এটি একই কারণে বেশ কয়েকটি শাঁস (না bash) cmd2ভিতরে অপেক্ষা করা বিরক্ত করে না cmd2 | cmd1

জন্য cmd1 >(cmd2), যদিও, সাধারণভাবে মামলা, এর যেমন আরো cmd2রয়েছে যা সাধারণত জন্য অপেক্ষা cmd1পর সাধারণত থেকে প্রস্থান করা হবে তাই।

এটি সেখানে zshঅপেক্ষা cmd2করাতে স্থির হয়েছে (তবে আপনি যদি এটি লিখেন cmd1 > >(cmd2)এবং cmd1বিল্টিন না হিসাবে লিখেন তবে ডকুমেন্টের{cmd1} > >(cmd2) পরিবর্তে ব্যবহার করুন )।

kshডিফল্টরূপে অপেক্ষা না করে, তবে আপনাকে waitবিল্টিনের সাথে এটির জন্য অপেক্ষা করতে দেয় (এটি পিডটি উপলব্ধ করে তোলে $!, যদিও এটি করলে আপনি সহায়তা করেন না cmd1 >(cmd2) >(cmd3))

rc( cmd1 >{cmd2}সিনট্যাক্স সহ), একই সাথে kshআপনি সমস্ত পটভূমি প্রক্রিয়াগুলির পিডস পেতে পারেন $apids

es(এছাড়াও সহ cmd1 >{cmd2}) cmd2পছন্দ করার zshজন্য অপেক্ষা করে cmd2এবং <{cmd2}প্রক্রিয়া পুনর্নির্দেশগুলির জন্যও অপেক্ষা করে ।

bashcmd2এটি সাবডেলের cmd2কোনও শিশু প্রক্রিয়াতে চালিত হওয়ার পরে (বা এটির শেষ কমান্ড হওয়া সত্ত্বেও সাবসেলের একেবারে হুবহু ) পাওয়া যায় $!তবে আপনাকে এটির জন্য অপেক্ষা করতে দেয় না।

যদি আপনার ব্যবহার bashকরতে হয় তবে আপনি একটি কমান্ড ব্যবহার করে সমস্যাটি সমাধান করতে পারেন যা উভয় কমান্ডের জন্য অপেক্ষা করবে:

{ { cmd1 >(cmd2); } 3>&1 >&4 4>&- | cat; } 4>&1

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

নোট করুন যে উপরে উল্লিখিত নষ্ট সাবস্কেল প্রক্রিয়াটির জন্য ধন্যবাদ, এটি cmd2তার এফডি 3 বন্ধ করলেও এটি কাজ করে (কমান্ডগুলি সাধারণত এটি করে না তবে কিছু পছন্দ করে sudoবা sshকরে)। ভবিষ্যতের সংস্করণগুলি bashঅন্যান্য শেলের মতো শেষ পর্যন্ত অপ্টিমাইজেশনটি করতে পারে। তারপরে আপনার এমন কিছু প্রয়োজন হবে:

{ { cmd1 >(sudo cmd2; exit); } 3>&1 >&4 4>&- | cat; } 4>&1

F sudoকমান্ডের অপেক্ষায় এইচডি 3 ওপেন সহ এখনও একটি অতিরিক্ত শেল প্রক্রিয়া রয়েছে তা নিশ্চিত করার জন্য ।

নোট করুন যে catকিছু পড়বে না (যেহেতু প্রক্রিয়াগুলি তাদের এফডি 3 তে লেখা হয় না)। এটি সিঙ্ক্রোনাইজেশনের জন্য ঠিক আছে। এটি কেবলমাত্র একটি read()সিস্টেম কল করবে যা শেষে কিছুই না করে ফিরে আসবে।

catপাইপ সিঙ্ক্রোনাইজেশন করতে আপনি কমান্ড প্রতিস্থাপন ব্যবহার করে চালানো এড়াতে পারবেন :

{ unused=$( { cmd1 >(cmd2); } 3>&1 >&4 4>&-); } 4>&1

এবার, এটির পরিবর্তে শেলটি catপাইপটি থেকে পড়ছে যার অন্য প্রান্তটি এফডি 3 cmd1এবং এর উপর খোলা আছে cmd2। আমরা একটি পরিবর্তনশীল অ্যাসাইনমেন্ট ব্যবহার করছি যাতে এর প্রস্থান স্থিতিটি cmd1পাওয়া যায় $?

অথবা আপনি নিজে হাতে প্রক্রিয়া প্রতিস্থাপন করতে পারেন, এবং তারপরে আপনি এমনকি আপনার সিস্টেমের ব্যবহারটি shএটি স্ট্যান্ডার্ড শেল সিনট্যাক্সে পরিণত করতে পারেন:

{ cmd1 /dev/fd/3 3>&1 >&4 4>&- | cmd2 4>&-; } 4>&1

যদিও নোট হিসাবে পূর্বে উল্লিখিত হয়েছে যে সমস্ত shবাস্তবায়ন শেষ cmd1হওয়ার পরে অপেক্ষা করবে না cmd2(যদিও এটি অন্য রাউন্ডের চেয়ে ভাল)। এই $?সময়টিতে প্রস্থান স্থিতি রয়েছে cmd2; যদিও bashএবং zshকরতে cmd1এর প্রস্থান পাওয়া অবস্থা ${PIPESTATUS[0]}এবং $pipestatus[1]যথাক্রমে (এছাড়াও দেখুন pipefailকয়েক শাঁস বিকল্পটি তাই $?গত ছাড়া অন্য পাইপ উপাদান ব্যর্থতার প্রতিবেদন করতে পারেন)

নোটটিতে yashএর প্রক্রিয়া পুনঃনির্দেশ বৈশিষ্ট্যটির সাথে একই রকম সমস্যা রয়েছে । সেখানে cmd1 >(cmd2)লেখা cmd1 /dev/fd/3 3>(cmd2)হবে। তবে এটির জন্য অপেক্ষা করা হয় না এবং আপনি এটির জন্য অপেক্ষাও cmd2করতে পারবেন না waitএবং এর পিডটি $!ভেরিয়েবলের মধ্যেও পাওয়া যায় না । আপনি প্রায় হিসাবে একই কাজ ব্যবহার করতে চাই bash


প্রথমত, আমি চেষ্টা করেছি echo one; { { echo two > >(cat); } 3>&1 >&4 4>&- | cat; } 4>&1; echo three;, তারপরে এটিকে সরল করে দিয়েছি echo one; echo two > >(cat) | cat; echo three;এবং এটি সঠিক ক্রমে মানগুলিও আউটপুট করে। এই সমস্ত বর্ণনামূলক হেরফের 3>&1 >&4 4>&-কি প্রয়োজনীয়? এছাড়াও, আমি এটি পাই না >&4 4>&- আমরা stdoutচতুর্থ এফডি তে পুনর্নির্দেশ করব , তারপরে চতুর্থ এফডি বন্ধ করব, তারপরে আবার 4>&1এটি ব্যবহার করুন। এটি কেন প্রয়োজন এবং এটি কীভাবে কাজ করে? হতে পারে, আমার এই বিষয়ে নতুন প্রশ্ন তৈরি করা উচিত?
মিনিম্যাক্স

1
@ মনিম্যাক্স, তবে সেখানে আপনি স্টাডাউটকে প্রভাবিত করছেন cmd1এবং cmd2ফাইল বর্ণনাকারীর সাথে সামান্য নাচের সাথে পয়েন্টটি মূলগুলি পুনরুদ্ধার করা এবং কমান্ডগুলির আউটপুট চ্যানেল না করে অপেক্ষা করার জন্য কেবল অতিরিক্ত পাইপ ব্যবহার করা ।
স্টাফেন চেজেলাস

@ মনিম্যাক্স বুঝতে আমার কিছুটা সময় লেগেছে, পাইপগুলি আমি এত কম স্তরে পাইনি আগে। ডানদিকের 4>&1বাইরের ধনুর্বন্ধনী কমান্ড তালিকার জন্য একটি ফাইল বর্ণনাকারী (fd) 4 তৈরি করে এবং এটি বাহ্যিক বন্ধনীগুলির স্টাডআউটের সমান করে তোলে। বাইরের ধনুর্বন্ধনীগুলির সাথে সংযোগ স্থাপনের জন্য অভ্যন্তরীণ ধনুর্বন্ধনীগুলিতে স্বয়ংক্রিয়ভাবে স্টিডিন / স্টডআউট / স্টার্ডার সেটআপ রয়েছে। তবে, 3>&1fd 3 কে বাইরের ধনুর্বন্ধনী 'স্টিডিনের সাথে সংযুক্ত করে। >&4ভিতরের ধনুর্বন্ধনী 'stdout বাইরের ধনুর্বন্ধনী fd 4 সাথে সংযুক্ত করে তোলে (আমরা আগে তৈরি করেছি)। 4>&-অভ্যন্তরীণ ধনুর্বন্ধনী থেকে এফডি 4 বন্ধ করে দেয় (যেহেতু অভ্যন্তরীণ ধনুর্বন্ধনী 'স্ট্টআউট ইতিমধ্যে আউট বন্ধনী' fd 4 এর সাথে সংযুক্ত রয়েছে))
নিকোলাস পিপিটোন

@ মিনিম্যাক্স বিভ্রান্তিকর অংশটি ডান থেকে বাম অংশ ছিল, 4>&1অন্য পুনর্নির্দেশের আগে প্রথমে মৃত্যুদন্ড কার্যকর করা হয়, সুতরাং আপনি "আবার ব্যবহার করবেন না 4>&1"। সামগ্রিকভাবে, অভ্যন্তরীণ ধনুর্বন্ধনী তার স্টডআউটে ডেটা প্রেরণ করছে, যা এফডি 4 দিয়েছিল তা দিয়ে ওভাররাইট করা হয়েছিল। অভ্যন্তরীণ ধনুর্বন্ধনী দেওয়া এফডি 4 হ'ল বাইরের ধনুর্বন্ধনী 'fd 4, যা বাইরের ধনুর্বন্ধকের মূল স্টাডাউটের সমান।
নিকোলাস পিপিটোন

বাশ এটিকে 4>5"4 5 এ যায়" এর মতো মনে করে , তবে সত্যই "fd 4 এফডি 5 দিয়ে ওভাররাইট করা হয়"। এবং মৃত্যুদন্ড কার্যকর করার আগে, এফডি 0/1/2 স্বয়ংক্রিয়ভাবে সংযুক্ত থাকে (বাইরের শেলের যে কোনও এফডি সহ) এবং আপনি তাদের ইচ্ছামত ওভাররাইট করতে পারেন। এটি কমপক্ষে আমার ব্যাশ ডকুমেন্টেশনের ব্যাখ্যা। তোমাদের মধ্যে অন্য কিছু আউট বোঝা যদি এই , lmk।
নিকোলাস পিপিটোন

4

আপনি দ্বিতীয় কমান্ডটি অন্যটিতে পাইপ করতে পারেন cat, এটির ইনপুট পাইপ বন্ধ না হওয়া পর্যন্ত অপেক্ষা করবে। উদা:

prompt$ echo one; echo two > >(cat) | cat; echo three;
one
two
three
prompt$

সংক্ষিপ্ত এবং সহজ।

==========

যতটা সহজ মনে হচ্ছে পর্দার আড়ালে অনেক কিছু চলছে। আপনি কীভাবে এটি কাজ করে তাতে আগ্রহী না হলে আপনি বাকী উত্তরটি উপেক্ষা করতে পারেন।

যখন আপনি echo two > >(cat); echo three, >(cat)ইন্টারেক্টিভ শেল দ্বারা বন্ধ করা forked, এবং স্বাধীনভাবে চালায় হয় echo two। সুতরাং, echo twoশেষ হয়, এবং তারপরে echo threeমৃত্যুদন্ড কার্যকর হয় তবে >(cat)শেষ হওয়ার আগে । কখন এটি প্রত্যাশিত ছিল না যখন bashথেকে ডেটা পাবেন >(cat)(পরে কয়েক মিলিয়ন সেকেন্ড), এটি আপনাকে সেই প্রম্পট-মতো পরিস্থিতি দেয় যেখানে আপনাকে টার্মিনালে ফিরে আসতে নিউলাইনটি চাপতে হবে (অন্য কোনও ব্যবহারকারী mesgআপনাকে এড করলে)।

তবে প্রদত্ত echo two > >(cat) | cat; echo three, দুটি সাব-শেল তৈরি হয়েছে ( |প্রতীকটির নথি অনুসারে )।

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

এর একটি সতর্কতা হ'ল বাশও তার জন্য একটি সাবস্কেল তৈরি করে >(cat)! এই কারণে, আপনি এটি দেখতে পাবেন

echo two > >(sleep 5) | cat; echo three

মৃত্যুদন্ড কার্যকর করার আগে 5 সেকেন্ড অপেক্ষা করবে echo three, যদিও sleep 5বি এর স্টিডিন ধরে না। এটি হ'ল কারণ একটি লুকানো সাবশেল সি >(sleep 5)অপেক্ষা করছে sleepএবং সি বি এর স্ট্ডিন ধরে রেখেছে। আপনি দেখতে পারেন কিভাবে

echo two > >(exec sleep 5) | cat; echo three

তবে অপেক্ষা করবেন না, যেহেতু sleepবি এর স্টাডিন ধরে নেই, এবং এমন কোনও ভূত সাবসেল সি নেই যা বি এর স্টিডিন ধরে রেখেছে (এক্সিকিউশন সি কে প্রতিস্থাপন করতে ঘুমকে বাধ্য করবে, সিটি অপেক্ষার বিরুদ্ধে এবং সি অপেক্ষার বিরোধী হিসাবে sleep)। এই সতর্কতা নির্বিশেষে,

echo two > >(exec cat) | cat; echo three

এখনও পূর্বে বর্ণিত হিসাবে সঠিকভাবে ফাংশন সম্পাদন করা হবে।


আমার উত্তরের মন্তব্যে @ মনিম্যাক্সের সাথে রূপান্তর হিসাবে উল্লিখিত হয়েছে, তবে এটি কমান্ডের স্টাডআউটকে প্রভাবিত করার নেতিবাচক দিক এবং এর অর্থ আউটপুটটি অতিরিক্ত সময় পড়তে হবে এবং লিখতে হবে।
স্টাফেন চেজেলাস

ব্যাখ্যাটি সঠিক নয়। মাতাল Aজন্য অপেক্ষা করছে catনা >(cat)। আমার উত্তরে আমি উল্লেখ করেছি যে, 5 সেকেন্ড পরে echo two > >(sleep 5 &>/dev/null) | cat; echo threeআউটপুট threeহওয়ার কারণ হ'ল বর্তমান সংস্করণগুলির bashঅপচয়গুলির অতিরিক্ত শেল প্রক্রিয়াটির >(sleep 5)জন্য অপেক্ষা করা হয় sleepএবং সেই প্রক্রিয়াটি এখনও স্টাডাউট pipeযা দ্বিতীয়টি catবন্ধ হতে বাধা দেয় । যদি আপনি echo two > >(exec sleep 5 &>/dev/null) | cat; echo threeঅতিরিক্ত অতিরিক্ত প্রক্রিয়াটি অপসারণ করতে এর সাথে প্রতিস্থাপন করেন তবে আপনি দেখতে পাবেন যে এটি সরাসরি চলে আসে।
স্টাফেন চেজেলাস

এটি একটি নেস্টেড সাবশেল করে তোলে? আমি এটি নির্ধারণের জন্য বাশ বাস্তবায়নটি খতিয়ে দেখার চেষ্টা করেছি, আমি নিশ্চিত যে echo two > >(sleep 5 &>/dev/null)ন্যূনতমতমটিতে তার নিজস্ব সাবશેল পাওয়া যায় pretty এটি কি কোনও নথিভুক্ত বাস্তবায়ন বিশদ যা sleep 5তার নিজস্ব সাবস্কেলটিও পেতে পারে? যদি এটি নথিভুক্ত হয় তবে এটি কম চরিত্রের সাথে এটি সম্পন্ন করার বৈধ উপায় হবে (যদি আপনি একটি দৃ tight় লুপ না করেন তবে আমি মনে করি না যে কেউ একটি সাবশেল, বা একটি বিড়ালের সাথে পারফরম্যান্সের সমস্যাগুলি লক্ষ্য করবে) `` যদি এটি নথিভুক্ত না হয় তবে চিপ, দুর্দান্ত হ্যাক যদিও ভবিষ্যতের সংস্করণগুলিতে কাজ করবে না।
নিকোলাস পিপিটোন

$(...), <(...)প্রকৃতপক্ষে একটি সাবসেল জড়িত করুন, তবে ksh93 বা zsh একই প্রক্রিয়াতে সেই সাবশেলে শেষ কমান্ডটি চালাবেন, তাই না bashকেন পাইপটি খোলার সময় অন্য প্রক্রিয়াটি খোলার সময় sleepনেই the ভবিষ্যতের সংস্করণগুলি bashঅনুরূপ অপ্টিমাইজেশন প্রয়োগ করতে পারে।
স্টাফেন চেজেলাস

1
@ স্টাফেনচাজেলাস আমি আমার উত্তর আপডেট করেছি এবং আমি মনে করি যে সংক্ষিপ্ত সংস্করণটির বর্তমান ব্যাখ্যা সঠিক, তবে আপনি শেলগুলির বাস্তবায়ন বিশদটি জানেন বলে আপনি যাচাই করতে পারেন। আমি মনে করি এই সমাধানটি ফাইল বর্ণনাকারী নৃত্যের বিপরীতে হিসাবে ব্যবহার করা উচিত, যদিও এর অধীনে থেকেও execএটি প্রত্যাশার মতো কাজ করে।
নিকোলাস পিপিটোন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.