সহযোগী অ্যারেগুলি ছাড়িয়ে, বাশে গতিশীল পরিবর্তনশীলগুলি অর্জনের বিভিন্ন উপায় রয়েছে। নোট করুন যে এই সমস্ত কৌশলগুলি ঝুঁকিগুলি উপস্থিত করে, যা এই উত্তরটির শেষে আলোচনা করা হয়েছে।
নিম্নলিখিত উদাহরণগুলিতে আমি ধরে নেব i=37
এবং আপনি যে ভেরিয়েবলটির var_37
প্রাথমিক মান তার নামটি দিতে চান lolilol
।
পদ্ধতি 1. একটি "পয়েন্টার" ভেরিয়েবল ব্যবহার করে
আপনি কেবল পরিবর্তিত পরিবর্তে ভেরিয়েবলের নাম সংরক্ষণ করতে পারেন, সি পয়েন্টারের বিপরীতে নয়। তারপরে বাশের আলিয়াস্ত ভেরিয়েবলটি পড়ার জন্য একটি বাক্য গঠন রয়েছে : ভেরিয়েবলের মানটিতে ${!name}
প্রসারিত হয় যার নাম ভেরিয়েবলের মান name
। আপনি এটিকে দ্বি-পর্যায়ে সম্প্রসারণ হিসাবে ভাবতে পারেন: ${!name}
প্রসারিত হয় $var_37
, যা প্রসারিত হয় lolilol
।
name="var_$i"
echo "$name" # outputs “var_37”
echo "${!name}" # outputs “lolilol”
echo "${!name%lol}" # outputs “loli”
# etc.
দুর্ভাগ্যক্রমে, এলিয়াসেড ভেরিয়েবলটি সংশোধন করার জন্য কোনও পাল্টা সিনট্যাক্স নেই । পরিবর্তে, আপনি নিম্নলিখিত কৌশলগুলির একটির সাথে অ্যাসাইনমেন্ট অর্জন করতে পারেন।
1A। দিয়ে বরাদ্দ করা হচ্ছেeval
eval
মন্দ, তবে আমাদের লক্ষ্য অর্জনের সবচেয়ে সহজ এবং বহনযোগ্য উপায়। অ্যাসাইনমেন্টের ডান দিকের দিক থেকে আপনাকে সাবধানে পালাতে হবে, কারণ এটি দুবার মূল্যায়ন করা হবে । এটি করার একটি সহজ এবং নিয়মতান্ত্রিক উপায় হ'ল ডান হাতের আগে মূল্যায়ন (বা ব্যবহার করা printf %q
)।
এবং আপনাকে ম্যানুয়ালি পরীক্ষা করে দেখতে হবে যে বাম দিকের দিকটি একটি বৈধ পরিবর্তনশীল নাম, বা সূচী সহ একটি নাম (এটি যদি তবে কী হত evil_code #
?)। বিপরীতে, নীচের অন্যান্য সমস্ত পদ্ধতি এটি স্বয়ংক্রিয়ভাবে প্রয়োগ করে।
# check that name is a valid variable name:
# note: this code does not support variable_name[index]
shopt -s globasciiranges
[[ "$name" == [a-zA-Z_]*([a-zA-Z_0-9]) ]] || exit
value='babibab'
eval "$name"='$value' # carefully escape the right-hand side!
echo "$var_37" # outputs “babibab”
downsides:
- পরিবর্তনশীল নামের বৈধতা পরীক্ষা করে না।
eval
মন্দ।
eval
মন্দ।
eval
মন্দ।
1B। দিয়ে বরাদ্দ করা হচ্ছেread
read
Builtin আপনি যদি একটি পরিবর্তনশীল, যার খবর আপনি নাম, একটা সত্য যা এখানে-স্ট্রিং সাথে শোষণ দিতে মান নির্ধারণ করতে দেয়:
IFS= read -r -d '' "$name" <<< 'babibab'
echo "$var_37" # outputs “babibab\n”
IFS
অংশ এবং বিকল্প -r
নিশ্চিত করুন যে মান হিসাবে হল নির্ধারিত হয়, যখন বিকল্প করতে -d ''
বহু-লাইন মান নির্ধারণ করতে পারবেন। এই শেষ বিকল্পটির কারণে, কমান্ডটি একটি শূন্য-বহির্গমন কোড সহ ফিরে আসে।
মনে রাখবেন, যেহেতু আমরা এখানে স্ট্রিং ব্যবহার করছি, একটি নতুন লাইন অক্ষরটি মানটিতে যুক্ত হবে।
downsides:
- কিছুটা অস্পষ্ট;
- একটি শূন্য-বহির্গমন কোডের সাথে ফিরে আসে;
- মানটিতে একটি নতুন লাইন সংযোজন করে।
1c। দিয়ে বরাদ্দ করা হচ্ছেprintf
বাশ ৩.১ (প্রকাশিত ২০০)) থেকে, printf
বিল্টিন তার ফলাফলটি এমন একটি ভেরিয়েবলের কাছেও অর্পণ করতে পারে যার নাম দেওয়া হয়েছে। পূর্ববর্তী সমাধানগুলির সাথে বিপরীতে, এটি কেবল কাজ করে, জিনিসগুলি থেকে বাঁচতে, বিভাজন রোধ করতে এবং এ জাতীয় আরও কিছু করার দরকার পড়ে না।
printf -v "$name" '%s' 'babibab'
echo "$var_37" # outputs “babibab”
downsides:
পদ্ধতি 2. একটি "রেফারেন্স" ভেরিয়েবল ব্যবহার করে
বাশ ৪.৩ (প্রকাশিত ২০১৪) থেকে, declare
বিল্টিনে -n
একটি ভেরিয়েবল তৈরির জন্য একটি বিকল্প রয়েছে যা অন্য একটি চলকটির কাছে "নাম উল্লেখ", অনেকটা সি ++ রেফারেন্সের মতো। মেথড 1-তে যেমন রেফারেন্সটি এলিয়াসেড ভেরিয়েবলের নাম সংরক্ষণ করে তবে প্রতিবার রেফারেন্স অ্যাক্সেস করা হয় (হয় পড়ার জন্য বা বরাদ্দ দেওয়ার জন্য), বাশ স্বয়ংক্রিয়ভাবে ইন্ডিয়ারেশনটি সমাধান করে।
উপরন্তু, ব্যাশ নিজের দ্বারা রেফারেন্স নিজেই, বিচারক মান পাবার জন্য একটি বিশেষ ও খুব বিভ্রান্তিকর শব্দবিন্যাস রয়েছে: ${!ref}
।
declare -n ref="var_$i"
echo "${!ref}" # outputs “var_37”
echo "$ref" # outputs “lolilol”
ref='babibab'
echo "$var_37" # outputs “babibab”
এটি নীচে বর্ণিত সমস্যাগুলি এড়ায় না, তবে কমপক্ষে এটি সিনট্যাক্সটিকে সোজা করে তোলে।
downsides:
ঝুঁকি
এই সমস্ত aliasing কৌশল বিভিন্ন ঝুঁকি উপস্থাপন। প্রতিবার আপনি ইন্ডিরিশনটি সমাধান করার সময় প্রথমটি স্বেচ্ছাসেবক কোড কার্যকর করছে (হয় পড়ার জন্য বা কার্যধারার জন্য) । প্রকৃতপক্ষে, স্কেলার ভেরিয়েবলের পরিবর্তে, পছন্দ মতো var_37
আপনি একটি অ্যারে সাবস্ক্রিপ্টও পছন্দ করতে পারেন arr[42]
। তবে বাশ প্রতিটি বারের মতো বর্গাকার বন্ধনীগুলির বিষয়বস্তুগুলির যাবতীয় মূল্যায়ন করার জন্য এটি মূল্যায়ন করে, তাই এলিয়াসিংয়ের arr[$(do_evil)]
উপর অপ্রত্যাশিত প্রভাব পড়তে পারে ... ফলস্বরূপ, আপনি যখন উলামের বংশবৃদ্ধি নিয়ন্ত্রণ করবেন তখন কেবল এই কৌশলগুলি ব্যবহার করুন ।
function guillemots() {
declare -n var="$1"
var="«${var}»"
}
arr=( aaa bbb ccc )
guillemots 'arr[1]' # modifies the second cell of the array, as expected
guillemots 'arr[$(date>>date.out)1]' # writes twice into date.out
# (once when expanding var, once when assigning to it)
দ্বিতীয় ঝুঁকিটি একটি চক্রীয় ওরফে তৈরি করছে। যেহেতু বাশ ভেরিয়েবলগুলি তাদের নামে নয় এবং তাদের স্কোপ দ্বারা চিহ্নিত করা হয়েছে, আপনি অজান্তেই নিজের কাছে একটি এলিফ তৈরি করতে পারেন (যখন এটি ভেবেছিলেন যে এটি একটি ঘেরের ক্ষেত্র থেকে একটি ভেরিয়েবল হবে)। সাধারণ ভেরিয়েবল নামগুলি ব্যবহার করার সময় এটি বিশেষত ঘটতে পারে (যেমন var
)। ফলস্বরূপ, আপনি যখন এলিয়াসেড ভেরিয়েবলের নামটি নিয়ন্ত্রণ করেন কেবল তখনই এই কৌশলগুলি ব্যবহার করুন ।
function guillemots() {
# var is intended to be local to the function,
# aliasing a variable which comes from outside
declare -n var="$1"
var="«${var}»"
}
var='lolilol'
guillemots var # Bash warnings: “var: circular name reference”
echo "$var" # outputs anything!
উৎস: