eval
এবং exec
উভয়ই বাশ (1) এর আদেশগুলিতে অন্তর্নির্মিত যা আদেশগুলি কার্যকর করে।
আমি আরও exec
কয়েকটি বিকল্প আছে দেখতে পাচ্ছি কিন্তু এটিই কেবল পার্থক্য? তাদের প্রসঙ্গে কি ঘটে?
eval
এবং exec
উভয়ই বাশ (1) এর আদেশগুলিতে অন্তর্নির্মিত যা আদেশগুলি কার্যকর করে।
আমি আরও exec
কয়েকটি বিকল্প আছে দেখতে পাচ্ছি কিন্তু এটিই কেবল পার্থক্য? তাদের প্রসঙ্গে কি ঘটে?
উত্তর:
eval
এবং exec
সম্পূর্ণ ভিন্ন জন্তু। (উভয়ই কমান্ড চালাবে এই কথাটি বাদে, তবে শেলটিতে আপনি যা কিছু করেন তা তাই করে))
$ help exec
exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
Replace the shell with the given command.
যা exec cmd
হয় তা ঠিক চালানোর মতোই cmd
, বর্তমান শেলটি পৃথক প্রক্রিয়া চালনার পরিবর্তে কমান্ড দ্বারা প্রতিস্থাপন করা হয়। অভ্যন্তরীণভাবে, চলমান বলুন একটি শিশু প্রক্রিয়া তৈরি করার জন্য /bin/ls
কল করবে fork()
এবং তারপরে exec()
বাচ্চাকে মৃত্যুদন্ড কার্যকর করতে হবে /bin/ls
। exec /bin/ls
অন্যদিকে কাঁটাচামচ হবে না , তবে কেবল শেলটি প্রতিস্থাপন করবে।
তুলনা করা:
$ bash -c 'echo $$ ; ls -l /proc/self ; echo foo'
7218
lrwxrwxrwx 1 root root 0 Jun 30 16:49 /proc/self -> 7219
foo
সঙ্গে
$ bash -c 'echo $$ ; exec ls -l /proc/self ; echo foo'
7217
lrwxrwxrwx 1 root root 0 Jun 30 16:49 /proc/self -> 7217
echo $$
আমি যে শেলটি শুরু করেছি তার পিআইডি মুদ্রণ করে এবং তালিকাটি শেল থেকে যে /proc/self
পিআইডি ls
চালিত হয়েছিল তা দেয়। সাধারণত, প্রক্রিয়া আইডি আলাদা হয় exec
তবে শেলের সাথে এবং ls
একই প্রক্রিয়া আইডি থাকে। এছাড়াও, exec
শেলটি প্রতিস্থাপন করা হওয়ার পরে নিম্নলিখিত কমান্ডটি চালিত হয়নি।
অন্য দিকে:
$ help eval
eval: eval [arg ...]
Execute arguments as a shell command.
eval
বর্তমান শেলটিতে একটি কমান্ড হিসাবে আর্গুমেন্টগুলি চালিত করবে। অন্য কথায় eval foo bar
ন্যায় হিসাবে একই foo bar
। কার্যকর করার আগে ভেরিয়েবলগুলি প্রসারিত হবে, সুতরাং আমরা শেল ভেরিয়েবলগুলিতে সংরক্ষিত কমান্ডগুলি কার্যকর করতে পারি:
$ unset bar
$ cmd="bar=foo"
$ eval "$cmd"
$ echo "$bar"
foo
এটি একটি শিশু প্রক্রিয়া তৈরি করবে না , সুতরাং চলকটি বর্তমান শেলটিতে সেট করা আছে। (অবশ্যই eval /bin/ls
কোনও শিশু প্রক্রিয়া তৈরি করবে, ঠিক একইভাবে একটি সরল বৃদ্ধা তৈরি /bin/ls
করবে))
অথবা আমাদের কাছে একটি কমান্ড থাকতে পারে যা শেল কমান্ড আউটপুট করে। দৌড়ানো ssh-agent
ব্যাকগ্রাউন্ডে এজেন্ট শুরু করে, এবং প্রচুর পরিমাণে পরিবর্তনশীল অ্যাসাইনমেন্ট আউটপুট দেয়, যা বর্তমান শেলটিতে সেট করা যেতে পারে এবং শিশু প্রক্রিয়াগুলি ব্যবহার করে (আপনি যে ssh
আদেশগুলি চালাতেন)। তাই ssh-agent
দিয়ে শুরু করা যেতে পারে:
eval $(ssh-agent)
এবং বর্তমান শেলটি অন্যান্য কমান্ডের উত্তরাধিকারের জন্য ভেরিয়েবলগুলি পাবে।
অবশ্যই, যদি ভেরিয়েবলের cmd
মতো এমন কিছু ঘটে থাকে rm -rf $HOME
তবে দৌড়ানো eval "$cmd"
আপনি যা করতে চান তা হ'ল না। এমনকি স্ট্রিংয়ের ভিতরে কমান্ড বিকল্পের মতো জিনিসগুলিও প্রক্রিয়াজাত করা হবে, তাই সত্যই নিশ্চিত হওয়া উচিত যে ইনপুটটি ব্যবহারের আগে এটি নিরাপদ।eval
প্রায়শই eval
দুর্ঘটনাক্রমে ভুল উপায়ে কোড এবং ডেটা মিশ্রণ করা এবং এড়ানো সম্ভব ।
eval
বিষয়ে সাধারণ অস্বীকৃতি যুক্ত করতে স্মরণ করিয়ে দেয় । পরোক্ষভাবে পরিবর্তনগুলি পরিবর্তন করার মতো স্টাফ অনেকগুলি শেলের মধ্যে declare
/ typeset
/ nameref
এবং বিস্তারের মাধ্যমে করা যেতে পারে ${!var}
, সুতরাং eval
যদি আমি সত্যিই এটি এড়াতে না পারি তবে আমি এর পরিবর্তে সেগুলি ব্যবহার করব।
exec
একটি নতুন প্রক্রিয়া তৈরি করে না। এটি বর্তমান কমান্ডটি নতুন কমান্ডের সাথে প্রতিস্থাপন করে। আপনি যদি কমান্ড লাইনে এটি করেন তবে কার্যকরভাবে এটি আপনার শেল সেশনটি শেষ করবে (এবং সম্ভবত আপনাকে লগ আউট করবে বা টার্মিনাল উইন্ডোটি বন্ধ করে দেবে!)
যেমন
ksh% bash
bash-4.2$ exec /bin/echo hello
hello
ksh%
এখানে আমি আছি ksh
(আমার সাধারণ শেল)। আমি শুরু করি bash
এবং তারপরে বাশের ভিতরে exec /bin/echo
। আমরা দেখতে পাচ্ছি যে আমাকে ksh
পরে পিছনে ফেলে দেওয়া হয়েছে কারণ bash
প্রক্রিয়াটি প্রতিস্থাপন করা হয়েছিল /bin/echo
।
exec
কোনও কমান্ড সুনির্দিষ্ট না করা থাকলে বর্তমান শেল প্রক্রিয়াটিকে নতুন এবং হ্যান্ডেল স্ট্রিম রিডাইরেকশন / ফাইল বর্ণনাকারীদের সাথে প্রতিস্থাপন করতে ব্যবহৃত হয়। eval
কমান্ড হিসাবে স্ট্রিং মূল্যায়ন করতে ব্যবহৃত হয়। উভয়ই রান-টাইমে পরিচিত আর্গুমেন্টগুলির সাথে একটি কমান্ড তৈরি এবং exec
সম্পাদন করতে ব্যবহৃত হতে পারে তবে কমান্ডগুলি কার্যকর করার সাথে সাথে বর্তমান শেলের প্রক্রিয়াটি প্রতিস্থাপন করে।
বাক্য গঠন:
exec [-cl] [-a name] [command [arguments]]
ম্যানুয়াল অনুসারে যদি কমান্ডটি অন্তর্নির্মিত নির্দিষ্ট করে থাকে
... শেল প্রতিস্থাপন। কোনও নতুন প্রক্রিয়া তৈরি হয় না। আর্গুমেন্ট কমান্ড আর্গুমেন্ট হয়ে।
অন্য কথায়, আপনি যদি bash
পিআইডি 1234 দিয়ে চালাচ্ছিলেন এবং যদি আপনি exec top -u root
সেই শেলের মধ্যে দৌড়াতে চান তবে top
কমান্ডটির পিআইডি 1234 থাকবে এবং আপনার শেল প্রক্রিয়াটি প্রতিস্থাপন করবে।
কোথায় এটি দরকারী? মোড়ক স্ক্রিপ্ট হিসাবে পরিচিত কিছু। এই ধরনের স্ক্রিপ্টগুলি আর্গুমেন্টগুলির সেট তৈরি করে বা পরিবেশে কী পরিবর্তনশীল তা নিয়ে নির্দিষ্ট সিদ্ধান্ত নেয় এবং তারপরে exec
যা কিছু আদেশ নির্দিষ্ট হয় তা দিয়ে নিজেকে প্রতিস্থাপন করতে ব্যবহার করে এবং অবশ্যই সেই একই যুক্তি সরবরাহ করে যা মোড়ক স্ক্রিপ্টটি সেই পথে তৈরি করেছে।
ম্যানুয়ালটিতে কী বলেছে তা হ'ল:
যদি কমান্ড নির্দিষ্ট না করা থাকে তবে বর্তমান শেলটিতে যে কোনও পুনর্নির্দেশ কার্যকর হবে
এটি আমাদের বর্তমান শেল আউটপুট স্ট্রিমগুলি থেকে কোনও ফাইলে পুনঃনির্দেশ করতে দেয়। এটি লগিং বা ফিল্টারিংয়ের উদ্দেশ্যে কার্যকর হতে পারে, যেখানে আপনি stdout
কেবল আদেশগুলি দেখতে চান না stderr
। উদাহরণস্বরূপ, যেমন:
bash-4.3$ exec 3>&1
bash-4.3$ exec > test_redirect.txt
bash-4.3$ date
bash-4.3$ echo "HELLO WORLD"
bash-4.3$ exec >&3
bash-4.3$ cat test_redirect.txt
2017年 05月 20日 星期六 05:01:51 MDT
HELLO WORLD
এই আচরণটি শেল স্ক্রিপ্টগুলিতে লগ ইন করতে , ফাইল বা প্রক্রিয়াগুলিকে পৃথক করে স্ট্রিমগুলিকে পুনঃনির্দেশকরণ এবং ফাইল বর্ণনাকারী সহ অন্যান্য মজাদার স্টাফকে সহজ করে তোলে ।
কমপক্ষে bash
4.3 সংস্করণের জন্য সোর্স কোড স্তরে exec
অন্তর্নির্মিতটি সংজ্ঞায়িত করা হয়েছে builtins/exec.def
। এটি প্রাপ্ত কমান্ডগুলি পার্স করে, এবং যদি কোনও থাকে তবে এটি ফাইলগুলিতে shell_execve()
সংজ্ঞায়িত জিনিসগুলিকে পাস করে execute_cmd.c
।
দীর্ঘ গল্প সংক্ষেপে, exec
সি প্রোগ্রামিং ভাষায় কমান্ডের একটি পরিবার উপস্থিত রয়েছে এবং shell_execve()
এটি মূলত execve
:
/* Call execve (), handling interpreting shell scripts, and handling
exec failures. */
int
shell_execve (command, args, env)
char *command;
char **args, **env;
{
ব্যাশ ৪.৩ ম্যানুয়াল স্টেটস (আমার দ্বারা জোর দেওয়া):
আরোগ্যগুলি একক কমান্ডের সাথে একত্রে পড়া এবং সংমিশ্রণ করা হয়। এর পরে এই কমান্ডটি শেল দ্বারা পড়া এবং সম্পাদন করা হয় এবং এর প্রস্থান স্থিতিটি eval এর মান হিসাবে ফিরে আসে is
মনে রাখবেন যে কোনও প্রক্রিয়া প্রতিস্থাপন ঘটছে না। exec
লক্ষ্যটি execve()
কার্যকারিতা অনুকরণ করা যেখানে তার বিপরীতে , eval
অন্তর্নির্মিতটি কেবল "মূল্যায়ন" যুক্তি সরবরাহ করে, ঠিক যেমন ব্যবহারকারী তাদের কমান্ড লাইনে টাইপ করেছেন। যেমন, নতুন প্রক্রিয়া তৈরি করা হয়।
কোথায় এটি দরকারী হতে পারে? গিলস যেমন এই উত্তরে উল্লেখ করেছেন যে , "... ইভাল খুব বেশি ব্যবহৃত হয় না। কিছু শেলের মধ্যে সর্বাধিক সাধারণ ব্যবহার এমন একটি চলকের মান অর্জন করা হয় যার নাম রানটাইম অবধি জানা যায় না"। ব্যক্তিগতভাবে, আমি এটি উবুন্টুতে বেশ কয়েকটি স্ক্রিপ্টে ব্যবহার করেছি যেখানে ব্যবহারকারী বর্তমানে নির্দিষ্ট ওয়ার্কস্পেসের উপর ভিত্তি করে একটি কমান্ড কার্যকর / মূল্যায়ন করা প্রয়োজন।
উত্স কোড স্তরে এটি সংজ্ঞায়িত করা হয় builtins/eval.def
এবং পার্সড ইনপুট স্ট্রিংটি evalstring()
কার্য করতে দেয়।
অন্যান্য বিষয়ের মধ্যে, eval
করতে ভেরিয়েবল নির্ধারণ যা বর্তমান শেল সঞ্চালনের পরিবেশে থাকা, যখন exec
না যা করতে পারেন:
$ eval x=42
$ echo $x
42
$ exec x=42
bash: exec: x=42: not found
একটি নতুন শিশু প্রক্রিয়া তৈরি করা, যুক্তি চালানো এবং প্রস্থান স্থিতি ফিরিয়ে দেওয়া।
আহ কি? পুরো বিষয়টি eval
হ'ল এটি কোনওভাবেই শিশু প্রক্রিয়া তৈরি করে না। যদি আমি করি
eval "cd /tmp"
একটি শেলের মধ্যে, তারপরে বর্তমান শেল ডিরেক্টরি পরিবর্তন হবে। উভয়ই exec
একটি নতুন শিশু প্রক্রিয়া তৈরি করে না , পরিবর্তে এটি প্রদত্ত সন্তানের জন্য বর্তমান এক্সিকিউটেবল (যথা শেল) পরিবর্তন করে; প্রক্রিয়া আইডি (এবং ফাইল এবং অন্যান্য সামগ্রী খুলুন) একই থাকে stay এর বিপরীতে eval
, এক্সিকিউটেবলকে খুঁজে পেতে বা লোড করতে না পেরে বা যুক্তি সম্প্রসারণের সমস্যার কারণে মারা না যাওয়ার কারণে নিজেই ব্যর্থ exec
না হলে কলিং শেলটিতে ফিরে আসবে না exec
।
eval
মূলত এর যুক্তি (গুলি) কে সংক্ষিপ্তকরণের পরে স্ট্রিং হিসাবে ব্যাখ্যা করে, যথা এটি ওয়াইল্ডকার্ড সম্প্রসারণ এবং যুক্তি বিভাজনের অতিরিক্ত স্তর করবে। exec
এরকম কিছু করে না
মূল্যায়ন
এই কাজ:
$ echo hi
hi
$ eval "echo hi"
hi
$ exec echo hi
hi
তবে, এটি না:
$ exec "echo hi"
bash: exec: echo hi: not found
$ "echo hi"
bash: echo hi: command not found
প্রক্রিয়া চিত্র প্রতিস্থাপন
এই উদাহরণটি প্রদর্শন করে যে exec
এটির কলিং প্রক্রিয়াটির চিত্রটি কীভাবে প্রতিস্থাপন করে:
# Get PID of current shell
sh$ echo $$
1234
# Enter a subshell with PID 5678
sh$ sh
# Check PID of subshell
sh-subshell$ echo $$
5678
# Run exec
sh-subshell$ exec echo $$
5678
# We are back in our original shell!
sh$ echo $$
1234
লক্ষ করুন যে, exec echo $$
subshell এর PID, সঙ্গে দৌড়ে! তদ্ব্যতীত, এটি সম্পূর্ণ হওয়ার পরে, আমরা আমাদের মূল sh$
শেল ফিরে এসেছি ।
অন্যদিকে, প্রক্রিয়া চিত্র প্রতিস্থাপন eval
করে না । বরং এটি প্রদত্ত কমান্ডটি চালায় যেমন আপনি সাধারণত শেলের মধ্যেই থাকেন। (অবশ্যই, যদি আপনি একটি কমান্ড চালনা করেন যার জন্য একটি প্রক্রিয়া তৈরি করা প্রয়োজন ... এটি ঠিক তাই করে!)
sh$ echo $$
1234
sh$ sh
sh-subshell$ echo $$
5678
sh-subshell$ eval echo $$
5678
# We are still in the subshell!
sh-subshell$ echo $$
5678
exec
)