কমান্ড হিসাবে পরিবর্তনশীল; eval বনাম bash -c


41

আমি একটি ব্যাশ স্ক্রিপ্ট কেউ তৈরি পড়া ছিল এবং আমি লক্ষ্য করেছি যে, লেখক একটি পরিবর্তনশীল একটি কমান্ড হিসাবে মূল্যায়নের Eval ব্যবহার করে না
লেখক ব্যবহৃত

bash -c "$1"

পরিবর্তে

eval "$1"

আমি ধরে নিচ্ছি ইওল ব্যবহার করা পছন্দসই পদ্ধতি এবং এটি সম্ভবত যাইহোক দ্রুত। এটা কি সত্যি?
দুজনের মধ্যে কি কোনও ব্যবহারিক পার্থক্য রয়েছে? দুজনের মধ্যে উল্লেখযোগ্য পার্থক্য কী?


কিছু অনুষ্ঠানে, আপনি ছাড়াও পালাতে পারেন। e='echo foo'; $eঠিক কাজ করে।
ডেনিস

উত্তর:


40

eval "$1"বর্তমান স্ক্রিপ্টে কমান্ড কার্যকর করে। এটি বর্তমান স্ক্রিপ্ট থেকে শেল ভেরিয়েবলগুলি সেট এবং ব্যবহার করতে পারে, বর্তমান স্ক্রিপ্টের জন্য পরিবেশের ভেরিয়েবলগুলি সেট করতে পারে, বর্তমান স্ক্রিপ্ট থেকে ফাংশনগুলি সেট এবং ব্যবহার করতে পারে, বর্তমান ডিরেক্টরিটি, উমাস্ক, সীমাবদ্ধতা এবং বর্তমান স্ক্রিপ্টের জন্য অন্যান্য বৈশিষ্ট্যগুলি সেট করতে পারে ইত্যাদি can bash -c "$1"সম্পূর্ণ পৃথক স্ক্রিপ্টে কমান্ডটি কার্যকর করে, যা পরিবেশের ভেরিয়েবল, ফাইল বর্ণনাকারী এবং অন্যান্য প্রক্রিয়া পরিবেশের উত্তরাধিকারী হয় (তবে কোনও পরিবর্তন ফিরে প্রেরণ করে না) তবে অভ্যন্তরীণ শেল সেটিংস (শেল ভেরিয়েবল, ফাংশন, বিকল্পগুলি, ট্র্যাপস ইত্যাদি) উত্তরাধিকার সূত্রে প্রাপ্ত হয় না।

আরও একটি উপায় আছে (eval "$1"), যা একটি সাবশেলে কমান্ডটি কার্যকর করে: এটি কলিং স্ক্রিপ্ট থেকে সমস্ত কিছু উত্তরাধিকার সূত্রে প্রাপ্ত হয় তবে কোনও পরিবর্তন ফিরে প্রেরণ করে না।

উদাহরণস্বরূপ, ধরে নিই যে চলকটি dirরফতানি করা হয়নি এবং $1তা হ'ল cd "$foo"; ls:

  • cd /starting/directory; foo=/somewhere/else; eval "$1"; pwd/somewhere/elseএবং মুদ্রণের বিষয়বস্তু তালিকাভুক্ত করে /somewhere/else
  • cd /starting/directory; foo=/somewhere/else; (eval "$1"); pwd/somewhere/elseএবং মুদ্রণের বিষয়বস্তু তালিকাভুক্ত করে /starting/directory
  • cd /starting/directory; foo=/somewhere/else; bash -c "$1"; pwd/starting/directory(কারণ cd ""বর্তমান ডিরেক্টরিটি পরিবর্তন করে না) এবং মুদ্রণের বিষয়বস্তু তালিকাভুক্ত করে /starting/directory

ধন্যবাদ। আমি (eval "$ 1") সম্পর্কে জানতাম না, এটি উত্স থেকে আলাদা কি?
হোয়ামি

1
@ হোয়ামির (eval "$1")কিছু করার নেই source। এটি কেবল (…)এবং এর সংমিশ্রণ evalsource fooমোটামুটিভাবে সমতূল্য eval "$(cat foo)"
গিলস 'দুষ্ট হওয়া বন্ধ করুন'

আমরা অবশ্যই আমাদের উত্তরগুলি একই সাথে
লিখছিলাম

@whoami মধ্যে মূল পার্থক্য evalএবং .dotযে evalসাথে কাজে আর্গুমেন্ট এবং .dotসাথে কাজ করে ফাইল।
মাইকসার্ভ

আপনাকে উভয় ধন্যবাদ। আমার আগের মন্তব্যটি আবার মূর্খ বলে মনে হচ্ছে যে আমি আবার এটি পড়েছি ...
হুয়ামি

23

এর মধ্যে সবচেয়ে গুরুত্বপূর্ণ পার্থক্য

bash -c "$1" 

এবং

eval "$1"

এটি কি পূর্বে একটি সাবশেলে চালায় এবং পরেরটি তা করে না। তাই:

set -- 'var=something' 
bash -c "$1"
echo "$var"

আউটপুট:

#there doesn't seem to be anything here
set -- 'var=something' 
eval "$1"
echo "$var"

আউটপুট:

something

যদিও কেউ কেন কখনও কার্যনির্বাহী bashসেভাবে ব্যবহার করতে পারে তা আমার কোনও ধারণা নেই । আপনার যদি এটির আবেদন করতেই হয় তবে অন্তর্নির্মিত গ্যারান্টিযুক্ত পোসিক্স ব্যবহার করুন sh। বা (subshell eval)আপনি যদি আপনার পরিবেশ রক্ষা করতে চান।

ব্যক্তিগতভাবে, আমি শেলকে .dotসর্বোপরি পছন্দ করি ।

printf 'var=something%d ; echo "$var"\n' `seq 1 5` | . /dev/fd/0

আউটপুট

something1
something2
something3
something4
something5

তবে আপনি কি সব কিছু প্রয়োজন?

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

এই ক্ষেত্রে:

var='echo this is var' ; $var

আউটপুট:

this is var

এটি কাজ করে তবে কেবল echoতার যুক্তি গণনা সম্পর্কে চিন্তা করে না।

var='echo "this is var"' ; $var

আউটপুট:

"this is var"

দেখা? ডাবল-কোটগুলি সাথে আসে কারণ শেলের সম্প্রসারণের $varফলাফলটির জন্য মূল্যায়ন হয় না quote-removal

var='printf %s\\n "this is var"' ; $var

আউটপুট:

"this
is
var"

তবে evalবা সাথে sh:

    var='echo "this is var"' ; eval "$var" ; sh -c "$var"

আউটপুট:

this is var
this is var

যখন আমরা ব্যবহার করি evalবা shশেলটি বিস্তারের ফলাফলগুলিতে দ্বিতীয় পাস নেয় এবং এগুলি একটি সম্ভাব্য কমান্ড হিসাবেও মূল্যায়ণ করে, এবং সুতরাং উদ্ধৃতিগুলি পৃথক হয়। আপনি এটি করতে পারেন:

. <<VAR /dev/fd/0
    ${var:=echo "this is var"}
#END
VAR

আউটপুট

this is var

5

আমি একটি দ্রুত পরীক্ষা করেছি:

time bash -c 'for i in {1..10000}; do bash -c "/bin/echo hi"; done'
time bash -c 'for i in {1..10000}; eval "/bin/echo hi"; done'

(হ্যাঁ, আমি জানি, আমি লুপটি কার্যকর করতে ব্যাশ-সি ব্যবহার করেছি তবে এতে কোনও পার্থক্য হওয়া উচিত নয়)।

ফলাফলগুলো:

eval    : 1.17s
bash -c : 7.15s

তাই evalদ্রুত। ম্যান পেজ থেকে eval:

Alভাল ইউটিলিটি এক সাথে যুক্তি যুক্ত করে একটি কমান্ড তৈরি করবে এবং প্রত্যেককে একটি চরিত্রের সাথে পৃথক করে। নির্মিত কমান্ডটি শেল দ্বারা পড়া এবং সম্পাদন করা হবে।

bash -cঅবশ্যই, বাশ শেলের কমান্ডটি কার্যকর করে। একটি নোট: আমি ব্যবহার করেছি /bin/echoকারণ echoএকটি শেলটি অন্তর্নির্মিত bash, যার অর্থ একটি নতুন প্রক্রিয়া শুরু করার দরকার নেই। প্রতিস্থাপন করা হচ্ছে /bin/echoসঙ্গে echoজন্য bash -cপরীক্ষা, সেটি নিয়ে 1.28s। যে একই সম্পর্কে। Hovever, evalএক্সিকিউটেবল চলমান জন্য দ্রুত। এখানে মূল পার্থক্যটি হ'ল evalনতুন শেলটি শুরু হয় না (এটি বর্তমানের মধ্যে কমান্ড কার্যকর করে) যেখানে bash -cএকটি নতুন শেল শুরু হয়, তারপরে নতুন শেলটিতে কমান্ডটি কার্যকর করা হয়। একটি নতুন শেল শুরু করতে সময় লাগে, এবং এ কারণেই bash -cধীর হয় eval


আমি ওপি তুলনা করতে চায় bash -cসঙ্গে evalনা exec
জোসেফ আর।

@JosephR। ওহো! আমি এটা পরিবর্তন করব।
প্লাজমা পাওয়ারটি

1
@JosephR। এটা এখন সংশোধন করা উচিত। এছাড়াও আমি পরীক্ষাগুলি আরও কিছুটা পুনরায় ভাগ করেছি এবং bash -cএটি খুব খারাপ নয় ...
প্লাজমা পাওয়ার

3
যদিও এটি সত্য, এটি কমান্ডটি বিভিন্ন পরিবেশে কার্যকর করা হয় এমন মৌলিক পার্থক্যটিকে মিস করে। এটি সুস্পষ্ট যে ব্যাশের নতুন উদাহরণ শুরু করা ধীর হবে, এটি আকর্ষণীয় পর্যবেক্ষণ নয়।
গিলস 'তাই খারাপ হওয়া বন্ধ করুন'
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.