শাঁস কেন কাঁটাচামচ কল ()?


32

শেল থেকে যখন কোনও প্রক্রিয়া শুরু হয়, প্রক্রিয়া চালানোর আগে কেন শেল নিজেই কাঁটাচামচ করে?

উদাহরণস্বরূপ, ব্যবহারকারী যখন ইনপুট দেয় grep blabla foo, তখন শেল exec()চাইল্ড শেল ছাড়া গ্রেপ-তে কল করতে পারে না কেন ?

এছাড়াও, যখন একটি শেল একটি জিইআইআই টার্মিনাল এমুলেটরটির মধ্যে কাঁটাচামচ করে, তখন এটি কি অন্য টার্মিনাল এমুলেটরটি শুরু করে? (যেমন pts/13শুরু pts/14)

উত্তর:


34

আপনি যখন কোনও execপরিবার পদ্ধতিতে কল করেন এটি কোনও নতুন প্রক্রিয়া তৈরি করে না, পরিবর্তে execবর্তমান প্রক্রিয়া মেমরি এবং নির্দেশ সেট ইত্যাদির পরিবর্তে আপনি চালাতে চান এমন প্রক্রিয়াটি প্রতিস্থাপন করে।

উদাহরণ হিসাবে, আপনি grepএক্সিকিউট ব্যবহার করে চালাতে চান । bashএকটি প্রক্রিয়া (যার পৃথক মেমরি, ঠিকানা স্থান রয়েছে)। এখন যখন আপনি কল করবেন exec(grep), এক্সিকিউটিভ বর্তমান প্রক্রিয়ার মেমরি, ঠিকানা স্থান, নির্দেশ সেট ইত্যাদি grep'sডেটা সহ প্রতিস্থাপন করবে । তার মানে bashপ্রক্রিয়া আর থাকবে না। ফলস্বরূপ আপনি grepকমান্ডটি শেষ করে টার্মিনালে ফিরে যেতে পারবেন না । এজন্যই এক্সিকিউটিভ পরিবার পদ্ধতিগুলি কখনই ফিরে আসে না। এক্সিকিউট করার পরে আপনি কোনও কোড কার্যকর করতে পারবেন না; এটা নাগালযোগ্য।


প্রায় ঠিক আছে --- আমি বাশ দিয়ে টার্মিনাল প্রতিস্থাপন করেছি। ;-)
রোমানো

2
বিটিডাব্লু, আপনি কমান্ডটি ব্যবহার করে প্রথমে কাঁটাচামচা না করে গ্রেপ চালাতে বাশকে বলতে পারেনexec grep blabla foo । অবশ্যই, এই বিশেষ ক্ষেত্রে এটি খুব কার্যকর হবে না (যেহেতু আপনার টার্মিনাল উইন্ডোটি গ্রেপ শেষ হওয়ার সাথে সাথেই বন্ধ হয়ে যাবে) তবে এটি মাঝে মাঝে কার্যকর হতে পারে (যেমন আপনি যদি অন্য শেলটি শুরু করেন তবে সম্ভবত এসএসএসের মাধ্যমে) / sudo / স্ক্রিন, এবং আসলটি ফিরে আসার ইচ্ছে করে না, বা আপনি যে শেল প্রক্রিয়াটি চালিয়ে যাচ্ছেন তা যদি একটি সাব-শেল হয় তবে এটি কখনও কখনও একাধিক কমান্ড কার্যকর করার উদ্দেশ্যে নয়)।
ইলমারি করোনেন

7
ইন্সট্রাকশন সেটটির খুব নির্দিষ্ট অর্থ রয়েছে specific আপনি এটি ব্যবহার করছেন এমন অর্থ এটি নয়
অ্যান্ড্রু সাবিনিখ

@ ইলমারিকারোনেন এটি মোড়ক স্ক্রিপ্টগুলিতে কার্যকর হবে যেখানে আপনি একটি আদেশের জন্য যুক্তি এবং পরিবেশ প্রস্তুত করতে চান। এবং আপনি যে কেসটি উল্লেখ করেছেন, যেখানে বাশ কখনই একাধিক কমান্ড চালানো বোঝায় না, এটি আসলে bash -c 'grep foo bar'এবং সেখানে এক্সিকিউটিভ কল করা অপ্টিমাইজেশান
ব্যাশের

3

মতে ptsএটি নিজে যাচাই করুন: শেলের মধ্যে, চালান

echo $$ 

আপনার প্রসেস-আইডি (পিআইডি) জানতে, আমার কাছে উদাহরণ রয়েছে

echo $$
29296

তারপরে উদাহরণস্বরূপ চালান sleep 60এবং তারপরে, অন্য টার্মিনালে

(0)samsung-romano:~% ps -edao pid,ppid,tty,command | grep 29296 | grep -v grep
29296  2343 pts/11   zsh
29499 29296 pts/11   sleep 60

সুতরাং না, সাধারণভাবে আপনার প্রক্রিয়াটির সাথে একই যুক্ত রয়েছে। (মনে রাখবেন এটি আপনার sleepকারণ পিতামাতার হিসাবে এটি আপনার শেল রয়েছে)।


2

টিএল; ডিআর : কারণ এটি নতুন প্রক্রিয়া তৈরি এবং ইন্টারেক্টিভ শেলটিতে নিয়ন্ত্রণ রক্ষার জন্য সর্বোত্তম পদ্ধতি

প্রক্রিয়া এবং পাইপগুলির জন্য কাঁটাচামচ () প্রয়োজনীয়

এই প্রশ্নের নির্দিষ্ট অংশের উত্তর দেওয়ার জন্য, যদি সরাসরি পিতামাতার grep blabla fooমাধ্যমে ডাকা exec()হত, পিতামাতার উপস্থিতি দখল করা হত, এবং সমস্ত সংস্থান সহ এর পিআইডি দখল করা হবে grep blabla foo

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

দ্বিতীয়ত, ইন্টারেক্টিভ শেলগুলি যতদূর যায়, আপনি কাঁটাচামচা ছাড়া কোনও বাহ্যিক কমান্ড চালাতে পারবেন না। ডিস্কে বাস করে এমন একটি এক্সিকিউটেবল চালু করতে (উদাহরণস্বরূপ /bin/df -h), আপনাকে কোনও exec()পারিবারিক ফাংশন কল করতে execve()হবে, যেমন , যা প্যারেন্টকে নতুন প্রক্রিয়াতে প্রতিস্থাপন করবে, এর পিআইডি এবং বিদ্যমান ফাইল বর্ণনাকারী ইত্যাদি গ্রহণ করবে। ইন্টারেক্টিভ শেলের জন্য, আপনি নিয়ন্ত্রণটি ব্যবহারকারীর কাছে ফিরে আসতে চান এবং পিতামাতাকে ইন্টারেক্টিভ শেল চালিয়ে যেতে দিন। সুতরাং, সবচেয়ে ভালো উপায় মাধ্যমে একটি subprocess তৈরি করা fork(), এবং যে প্রক্রিয়া মাধ্যমে অধিগৃহীত করা যাক execve()। সুতরাং ইন্টারেক্টিভ শেল পিআইডি 1156 fork()পিআইডি 1157 এর মাধ্যমে কোনও শিশুকে স্পোন করবে , তারপরে কল করবে execve("/bin/df",["df","-h"],&environment)যা /bin/df -hপিআইডি 1157 দিয়ে রান করে। এখন শেলটি কেবল প্রসেসের বাইরে বেরিয়ে আসার জন্য অপেক্ষা করতে হবে এবং এতে নিয়ন্ত্রণ ফিরে আসতে পারে।

আপনি যেখানে দুটি বা ততোধিক কমান্ডের মধ্যে একটি পাইপ তৈরি df | grepকরতে হবে , সেখানে বলুন , আপনার দুটি ফাইল বর্ণনাকারী তৈরি করার একটি উপায় প্রয়োজন (এটি pipe()সাইকাল থেকে আসা পাইপের শেষ অংশ পড়া এবং লেখার জন্য ), তবে কোনওভাবে দুটি নতুন প্রক্রিয়া তাদের উত্তরাধিকার সূত্রে আসুক। এটি নতুন প্রক্রিয়াটি কাঁটাচামচ করা এবং তারপরে পাইপটির লেখার প্রান্তটি dup2()তার stdoutউফ এফডি 1 এ কল করে অনুলিপি করে (সুতরাং লেখার শেষটি এফডি 4 হয়, তবে আমরা করি dup2(4,1))। যখন exec()স্পোন dfহয় তখন শিশু প্রক্রিয়াটি তার কিছুই ভাববে না stdoutএবং সচেতন না হয়ে এটিকে লিখবে (যদি না এটি সক্রিয়ভাবে পরীক্ষা করে থাকে) যে তার আউটপুটটি আসলে পাইপ হয়ে যায়। একই প্রক্রিয়া ঘটবে grep, আমরা ছাড়া fork(), FD 3 এবং পাইপের পঠিত শেষ নেওয়া dup(3,0)ডিম ছাড়ার আগে grepসঙ্গেexec()। এই সমস্ত সময় পিতামাতার প্রক্রিয়া এখনও আছে, একবার পাইপলাইন শেষ হয়ে গেলে আবার নিয়ন্ত্রণ ফিরে পাওয়ার অপেক্ষায়।

এর বিল্ট-ইন কমান্ড, সাধারণত শেল যদি না fork()বাদ দিয়ে, sourceকমান্ড। সাবসেলের প্রয়োজন fork()

সংক্ষেপে, এটি একটি প্রয়োজনীয় এবং দরকারী প্রক্রিয়া।

কাঁটাচামচ করা এবং অনুকূলিতকরণের অসুবিধা ages

এখন, এই হল নন-ইন্টারেক্টিভ শেল জন্য বিভিন্ন যেমন bash -c '<simple command>'fork()/exec()সর্বোত্তম পদ্ধতি হওয়া সত্ত্বেও যেখানে আপনাকে অনেকগুলি কমান্ড প্রক্রিয়াকরণ করতে হয়, এটি যখন আপনার কেবলমাত্র একটি একক কমান্ড থাকে তখন এটি সম্পদের অপচয় হয়। এই পোস্ট থেকে স্টাফেন চেজেলাসের উদ্ধৃতি দিতে :

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

অতএব, অনেকগুলি শেল (কেবল নয় bash) সেই একক সাধারণ কমান্ড দ্বারা এটি নিয়ন্ত্রণ exec()করার অনুমতি দেয় bash -c ''। এবং ঠিক উপরে বর্ণিত কারণগুলির জন্য, শেল স্ক্রিপ্টগুলিতে পাইপলাইনগুলি হ্রাস করা আরও ভাল। প্রায়শই আপনি দেখতে পারা যায় নবজাতকরা এরকম কিছু করেন:

cat /etc/passwd | cut -d ':' -f 6 | grep '/home'

অবশ্যই, এটি fork()3 প্রক্রিয়া করবে । এটি একটি সাধারণ উদাহরণ, তবে গিগাবাইটের পরিসীমাতে একটি বৃহত ফাইল বিবেচনা করুন। এটি একটি প্রক্রিয়ার সাথে আরও দক্ষ হতে চাই:

awk -F':' '$6~"/home"{print $6}' /etc/passwd

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

অবশ্যই এর অর্থ এই নয় যে কাঁটাচামচ করা কেবল খারাপ। এটি এখনও আগে যেমন আলোচিত একটি কার্যকর প্রক্রিয়া, তবে আপনি যেখানে কম প্রক্রিয়া, এবং ক্রমাগত কম সংস্থান এবং আরও ভাল পারফরম্যান্স নিয়ে দূরে সরে যেতে fork()পারেন সেখানে যদি সম্ভব হয় তবে আপনার এড়ানো উচিত ।

আরো দেখুন


1

বাশ প্রম্পটে প্রদত্ত প্রতিটি কমান্ডের (উদাহরণস্বরূপ: গ্রেপ) আপনি আসলে একটি নতুন প্রক্রিয়া শুরু করতে চান এবং তারপরে মৃত্যুদন্ড কার্যকর হওয়ার পরে বাশ প্রম্পটে ফিরে আসবেন।

যদি শেল প্রক্রিয়া (বাশ) এক্সিকিউটি () কে গ্রেপ চালাতে কল করে, শেল প্রক্রিয়াটি গ্রেপের সাথে প্রতিস্থাপন করা হবে। গ্রেপ সূক্ষ্মভাবে কাজ করবে তবে কার্যকর করার পরে, নিয়ন্ত্রণটি শেলের কাছে ফিরে আসতে পারে না কারণ ব্যাশ প্রক্রিয়া ইতিমধ্যে প্রতিস্থাপন করা হয়েছে।

এই কারণে, ব্যাশ কাঁটাচামচ কল করে (), যা বর্তমান প্রক্রিয়া প্রতিস্থাপন করে না।

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