Eval ব্যবহার করে বাশনে ভেরিয়েবলগুলিতে স্থান-সমেত মানগুলি কীভাবে নির্ধারণ করা যায়


19

আমি পরিবর্তনশীল ব্যবহার করে পরিবর্তনশীল মান পরিবর্তন করতে চাই eval। নিম্নলিখিত ডামি উদাহরণ কাজ করে:

var_name="fruit"
var_value="orange"
eval $(echo $var_name=$var_value)
echo $fruit
orange

যাইহোক, যখন ভেরিয়েবলের মানটিতে স্পেস থাকে, evalএকটি ত্রুটি প্রদান করে, এমনকি $var_valueডাবল কোটের মধ্যে রাখলেও:

var_name="fruit"
var_value="blue orange"
eval $(echo $var_name="$var_value")
bash: orange : command not found

এটির কোন উপায়?

উত্তর:



11

এর evalজন্য ব্যবহার করবেন না ; ব্যবহার declare

var_name="fruit"
var_value="blue orange"
declare "$var_name=$var_value"

মনে রাখবেন যে শব্দ বিভাজন কোনও সমস্যা নয়, কারণ নিম্নলিখিতটি অনুসরণ করা সমস্ত =কিছুই declareকেবল প্রথম শব্দের দ্বারা নয়, মান হিসাবে বিবেচিত হয় ।

ইন bash4.3 নাম রেফারেন্স এই একটি সামান্য সহজ ভুলবেন না।

$ declare -n var_name=fruit
$ var_name="blue orange"
$ echo $fruit
blue orange

আপনি কাজ করতে পারেন eval, তবে আপনার এখনও হওয়া উচিত নয় :) ব্যবহার evalকরা খারাপ অভ্যাস getোকা।

$ eval "$(printf "%q=%q" "$var_name" "$var_value")"

2
eval সেভাবে ব্যবহার করা ভুল। আপনি $var_valueএটি পাস করার আগে সম্প্রসারণ করছেন evalযার অর্থ এটি শেল কোড হিসাবে ব্যাখ্যা করা হবে! (উদাহরণস্বরূপ চেষ্টা করুন var_value="';:(){ :|:&};:'")
স্টাফেন চেজেলাস

1
ভাল যুক্তি; কিছু স্ট্রিং রয়েছে যা আপনি নিরাপদে ব্যবহার করে নির্ধারণ করতে পারবেন না eval( এটির এক কারণ যা বলেছি যে আপনি ব্যবহার করবেন না eval)।
চিপনার

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

আমি ঠিক করেছি মনে evalব্যবহার printfএবং তার bash-specific %qবিন্যাস। এটি এখনও ব্যবহারের জন্য কোনও প্রস্তাবনা নয় eval, তবে আমি মনে করি এটি এটি আগের চেয়ে নিরাপদ। এটিকে কাজে লাগানোর জন্য আপনাকে এই প্রচেষ্টায় যাওয়ার দরকার এই প্রমাণটি declareপরিবর্তে আপনার ব্যবহার করা বা নামকরণ করা উচিত ।
চিপনার

আসলে, আমার মতে, নাম উল্লেখ করা সমস্যা the এটির ব্যবহারের সর্বোত্তম উপায় - আমার অভিজ্ঞতা - এটির মতো ... set -- a bunch of args; eval "process2 $(process1 "$@")"যেখানে process1কেবল উদ্ধৃত সংখ্যাগুলি প্রিন্ট করে "${1}" "${8}" "${138}"। এটি ক্রেজি সহজ - এবং '"${'$((i=$i+1))'}" 'বেশিরভাগ ক্ষেত্রে যেমন সহজ । সূচিকাগুলি উল্লেখগুলি এটিকে নিরাপদ, মজবুত এবং দ্রুত করে তোলে । তবুও - আমি upvated।
মাইকজার্ভ

4

evalএটির সাথে কাজ করার একটি ভাল উপায় এটি echoপরীক্ষার জন্য প্রতিস্থাপন করা । echoএবং evalএকই কাজ করুন (যদি আমরা \xকিছু echoবাস্তবায়নের মতো bashকিছু শর্তে এর সম্প্রসারণটি আলাদা করে রাখি )।

উভয় কমান্ডই তাদের যুক্তিতে এর মধ্যে একটি জায়গার সাথে যুক্ত হয়। পার্থক্যটি হ'ল ফলাফলটি শেল কোড হিসাবে মূল্যায়ন / ব্যাখ্যা করার সময় ফলাফলটি echo প্রদর্শন করে ।eval

সুতরাং, শেল কোড দেখতে

eval $(echo $var_name=$var_value)

মূল্যায়ন করতে হবে, আপনি চালাতে পারেন:

$ echo $(echo $var_name=$var_value)
fruit=blue orange

এটি আপনি যা চান তা নয়, আপনি যা চান তা হ'ল:

fruit=$var_value

এছাড়াও, $(echo ...)এখানে ব্যবহার করার অর্থ নেই doesn't

উপরের আউটপুট আউট করতে, আপনি চালাতে চাই:

$ echo "$var_name=\$var_value"
fruit=$var_value

সুতরাং, এটি ব্যাখ্যা করতে, এটি সহজ:

eval "$var_name=\$var_value"

নোট করুন এটি পৃথক অ্যারে উপাদান সেট করতেও ব্যবহার করা যেতে পারে:

var_name='myarray[23]'
var_value='something'
eval "$var_name=\$var_value"

অন্যরা যেমন বলেছে, আপনি যদি নিজের কোডটি bashনির্দিষ্ট বলে যত্নবান না করেন তবে আপনি এটি ব্যবহার করতে পারেন declare:

declare "$var_name=$var_value"

তবে মনে রাখবেন এর কিছু পার্শ্ব প্রতিক্রিয়া রয়েছে।

এটি ভেরিয়েবলের ব্যাপ্তিটি যেখানে কাজ করে সেখানে সীমাবদ্ধ করে So সুতরাং আপনি উদাহরণ হিসাবে এটি ব্যবহার করতে পারবেন না:

setvar() {
  var_name=$1 var_value=$2
  declare "$var_name=$var_value"
}
setvar foo bar

কারণ এটি একটি ঘোষণা করবে foo ভেরিয়েবল স্থানীয় setvarহিসাবে ঘোষিত হবে অকেজো হবে।

bash-4.2গ্লোবাল ভেরিয়েবল ঘোষণার -gজন্য একটি বিকল্প যুক্ত করা হয়েছে , তবে আমরা যা চাই তা নয় এটি যেহেতু আমাদের আহ্বানকারী যদি কলার একটি ফাংশন থাকে তবে তার বিপরীতে একটি বৈশ্বিক ভার সেট করত :declaresetvar

setvar() {
  var_name=$1 var_value=$2
  declare -g "$var_name=$var_value"
}
foo() {
  local myvar
  setvar myvar 'some value'
  echo "1: $myvar"
}
foo
echo "2: $myvar"

যা আউটপুট হবে:

1:
2: some value

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

এই ক্ষেত্রে:

varname=foo
varvalue='([PATH=1000]=something)'
declare "$varname=$varvalue"

varnameপূর্বে স্কেলার , অ্যারে বা এসোসিয়েটিভ অ্যারে হিসাবে ঘোষিত হলে একটি আলাদা ফলাফল (এবং সম্ভাব্য দুষ্টু পার্শ্ব প্রতিক্রিয়া) তৈরি করবে ।


2
বাশ সুনির্দিষ্ট হওয়ার সাথে কী সমস্যা? ওপি প্রশ্নের উপর ব্যাশ ট্যাগ রেখেছিল, সুতরাং সে ব্যাশ ব্যবহার করছে। বিকল্প সরবরাহ করা ভাল, তবে আমি মনে করি কাউকে শেলের বৈশিষ্ট্য না ব্যবহার করা বলা কারণ এটি পোর্টেবল নয় বোকা।
প্যাট্রিক

@ পেট্রিক, হাসি দেখছেন? এটি বলার পরেও, পোর্টেবল সিনট্যাক্স ব্যবহারের অর্থ কম প্রচেষ্টা মানে যখন আপনার কোডটি অন্য সিস্টেমে পোর্ট করার দরকার নেই যেখানে bashউপলব্ধ নেই (বা যখন আপনি বুঝতে পারেন আপনার আরও ভাল / দ্রুত শেল প্রয়োজন)। evalসব বোর্ন মত শাঁস সিনট্যাক্স কাজ করে এবং POSIX তাই সমস্ত সিস্টেমে একটি থাকবে shযেখানে যে কাজ করে। (এর অর্থ হ'ল আমার উত্তরটি সমস্ত শেলের ক্ষেত্রে প্রযোজ্য, এবং খুব শীঘ্রই বা পরে, যেমনটি প্রায়শই এখানে ঘটে যায়, আপনি দেখতে পাবে একটি নন-বাশ নির্দিষ্ট প্রশ্নটির
উত্তরটির

কিন্তু যদি $var_nameটোকেন থাকে? ... মত ;?
মাইকজার্ভ

@ মাইক্রোজার, তাহলে এটি কোনও পরিবর্তনশীল নাম নয়। আপনি এটির সামগ্রী বিশ্বাস করতে পারি না, তাহলে তোমাদের সাথে এটা নির্বিষ করার প্রয়োজন evalএবং declare(চিন্তা PATH, TMOUT, PS4, SECONDS...)।
স্টাফেন চেজেলাস

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

1

যদি তুমি করো:

eval "$name=\$val"

... এবং $nameএতে একটি ;- বা অন্য কয়েকটি টোকেন রয়েছে যা শেলটি একটি সাধারণ কমান্ডের সীমাবদ্ধ হিসাবে ব্যাখ্যা করতে পারে - এর আগে যথাযথ শেল সিনট্যাক্স, এটি কার্যকর করা হবে।

name='echo hi;varname' val='be careful with eval'
eval "$name=\$val" && echo "$varname"

আউটপুট

hi
be careful with eval

যদিও কখনও কখনও এই জাতীয় বিবৃতিগুলির মূল্যায়ন এবং সম্পাদন পৃথক করা সম্ভব হয়। উদাহরণস্বরূপ, aliasকমান্ডের প্রাক-মূল্যায়ন করতে ব্যবহার করা যেতে পারে। নিম্নলিখিত উদাহরণে ভেরিয়েবল সংজ্ঞা এমনটিতে সংরক্ষণ করা হয় aliasযা কেবলমাত্র সফলভাবে ঘোষণা করা যেতে পারে যদি $nmএটির পরিবর্তনশীল মূল্যায়ন করা হয় তবে এমন কোনও বাইট নেই যা ASCII অক্ষরের সাথে মেলে না বা _

LC_OLD=$LC_ALL LC_ALL=C
alias "${nm##*[!_A-Z0-9a-z]*}=_$nm=\$val" &&
eval "${nm##[0-9]*}" && unalias "$nm"
LC_ALL=$LC_OLD

evalএখানে aliasএকটি বর্ণনাম থেকে নতুনকে ডাকে পরিচালনা করতে ব্যবহার করা হয় । তবে পূর্ববর্তী aliasসংজ্ঞাটি সফল হলে এটিকে কেবলমাত্র ডাকা হয় এবং আমি জানি যে বিভিন্ন বাস্তবায়ন অনেকগুলি aliasনামের জন্য বিভিন্ন ধরণের মান গ্রহণ করবে , আমি এখনও এমন একটিতে প্রবেশ করি নি যা সম্পূর্ণ শূন্যটি গ্রহণ করবে will ।

মধ্যে সংজ্ঞা aliasজন্য _$nmঅবশ্য, এবং এই তা নিশ্চিত করার জন্য কোন উল্লেখযোগ্য পরিবেশ মান উপর লিখিত হয়। আমি কোনও উল্লেখযোগ্য পরিবেশের মান জানি না যেটি শুরু হয় _এবং এটি প্রায়শই আধা-বেসরকারী ঘোষণার জন্য একটি নিরাপদ বাজি।

যাইহোক, aliasসংজ্ঞাটি সফল হলে এটি এর মানটির aliasজন্য একটি নাম ঘোষণা করবে $nm। এবং evalকেবলমাত্র এটি কল করবে aliasযদি এছাড়াও একটি সংখ্যা দিয়ে শুরু না হয় - অন্যথায় evalকেবল একটি নাল যুক্তি পায়। সুতরাং যদি উভয় শর্ত পূরণ হয় তবে উপনামকে evalকল করা হয় এবং উপন্যাসে সংরক্ষিত চলক সংজ্ঞাটি তৈরি করা হয়, যার পরে aliasনতুনটিকে তাত্ক্ষণিকভাবে হ্যাশ টেবিল থেকে সরানো হয়।


;পরিবর্তনশীল নামে অনুমোদিত নয়। যদি বিষয়বস্তুতে আপনার নিয়ন্ত্রণ না থাকে $nameতবে আপনার জন্য এটির জন্য export/ declareপাশাপাশি স্যানিটাইজ করা প্রয়োজন । যদিও exportকোড এক্সিকিউট না, মত কিছু ভেরিয়েবলের মান স্থাপনার PATH, PS4এবং যারা অনেক সময়ে info -f bash -n 'Bash Variables'সমানভাবে বিপজ্জনক পার্শ্বপ্রতিক্রিয়া আছে।
স্টাফেন চ্যাজেলাস

@ স্টাফেনচাজেলাস - অবশ্যই এটি অনুমোদিত নয়, তবে আগের মতো evalএটি এর প্রথম পাসের একটি ভেরিয়েবল নাম নয় - এটি একটি পরিবর্তনশীল সম্প্রসারণ। আপনি অন্য কোথাও বলেছিলেন, সেই প্রসঙ্গে এটি খুব অনুমোদিত। তবুও AT पथ আর্গুমেন্টটি খুব ভাল - আমি একটি ছোট সম্পাদনা করেছি এবং পরে এটি যুক্ত করব।
মাইকজার্ভ

@ স্টাফেনচাজেলাস - আগের চেয়ে ভাল দেরী ...?
মাইকসার্ভ

বাস্তবে, zsh, pdksh, mksh, yashউপর অভিযোগ না unset 'a;b'
স্টাফেন চেজেলাস

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