এটি ইউনিক্সের বিভিন্ন প্রশ্নে আলোচনা করা হয়েছে। এসইএস, আমি এখানে যে সমস্ত বিষয় নিয়ে আসতে পারি তা সংগ্রহ করার চেষ্টা করব। শেষে রেফারেন্স।
কেন এটি ব্যর্থ হয়
আপনি এই সমস্যার মুখোমুখি হওয়ার কারণ হ'ল শব্দ বিভাজন এবং ভেরিয়েবল থেকে প্রসারিত উদ্ধৃতিগুলি উদ্ধৃতি হিসাবে কাজ করে না, তবে এটি কেবলমাত্র সাধারণ চরিত্র।
প্রশ্নে উপস্থাপিত মামলাগুলি:
$ abc='ls -l "/tmp/test/my dir"'
এখানে $abc
বিভক্ত হয়ে ls
দুটি যুক্তি "/tmp/test/my
এবং dir"
(প্রথমটির দ্বিতীয় এবং দ্বিতীয়টির পিছনে উদ্ধৃতি সহ) পাওয়া যায়:
$ $abc
ls: cannot access '"/tmp/test/my': No such file or directory
ls: cannot access 'dir"': No such file or directory
এখানে, সম্প্রসারণের উদ্ধৃতি দেওয়া হয়েছে, সুতরাং এটি একটি শব্দ হিসাবে রাখা হয়েছে। শেলটি একটি প্রোগ্রাম হিসাবে সন্ধান করার চেষ্টা করে ls -l "/tmp/test/my dir"
, স্থান এবং কোট অন্তর্ভুক্ত।
$ "$abc"
bash: ls -l "/tmp/test/my dir": No such file or directory
এবং এখানে, কেবল প্রথম শব্দটি বা $abc
তর্ক হিসাবে বিবেচিত হয় -c
, সুতরাং বাশ কেবলমাত্র ls
বর্তমান ডিরেক্টরিতে চালিত হয়। অন্য কথায় ব্যাশ আর্গুমেন্ট আছে, এবং পূরণ করতে ব্যবহার করা হয় $0
, $1
ইত্যাদি
$ bash -c $abc
'my dir'
সহ bash -c "$abc"
, এবং eval "$abc"
, একটি অতিরিক্ত শেল প্রসেসিং পদক্ষেপ রয়েছে, যা কোটগুলি কার্যকর করে তোলে, তবে সমস্ত শেল বিস্তৃতি আবার প্রক্রিয়াজাতকরণের কারণও বটে , সুতরাং ব্যবহারকারী-সরবরাহিত ডেটা থেকে ঘটনাক্রমে কমান্ড সম্প্রসারণের ঝুঁকি রয়েছে, যদি আপনি না হন উদ্ধৃতি সম্পর্কে সাবধান।
এটি করার আরও ভাল উপায়
কমান্ড সংরক্ষণের আরও দুটি ভাল উপায় হ'ল ক) পরিবর্তে একটি ফাংশন ব্যবহার করুন, খ) একটি অ্যারে ভেরিয়েবল (বা অবস্থানিক পরামিতি) ব্যবহার করুন।
একটি ফাংশন ব্যবহার করে:
কেবল কমান্ডটি ভিতরে ভিতরে একটি ক্রিয়াকলাপ ঘোষণা করুন, এবং এটি একটি আদেশ হিসাবে যেন ফাংশনটি চালান। ফাংশনটির মধ্যে কমান্ডগুলির বিস্তৃতি কেবলমাত্র যখন কমান্ডটি চালিত হয় তখনই প্রক্রিয়া করা হয়, যখন এটি সংজ্ঞায়িত হয় না, এবং আপনাকে পৃথক কমান্ডের উদ্ধৃতি দেওয়ার প্রয়োজন হয় না।
# define it
myls() {
ls -l "/tmp/test/my dir"
}
# run it
myls
একটি অ্যারে ব্যবহার:
অ্যারেগুলি একাধিক-শব্দ ভেরিয়েবল তৈরি করতে দেয় যেখানে পৃথক শব্দের মধ্যে সাদা স্থান থাকে। এখানে, পৃথক শব্দগুলি পৃথক অ্যারে উপাদান হিসাবে সংরক্ষণ করা হয় এবং "${array[@]}"
প্রসারণ প্রতিটি উপাদানকে পৃথক শেল শব্দ হিসাবে প্রসারিত করে:
# define the array
mycmd=(ls -l "/tmp/test/my dir")
# run the command
"${mycmd[@]}"
বাক্য গঠনটি খানিকটা ভয়ঙ্কর, তবে অ্যারে আপনাকে কমান্ড লাইন টুকরো টুকরো করে তৈরি করতে দেয়। উদাহরণ স্বরূপ:
mycmd=(ls) # initial command
if [ "$want_detail" = 1 ]; then
mycmd+=(-l) # optional flag
fi
mycmd+=("$targetdir") # the filename
"${mycmd[@]}"
অথবা কমান্ড লাইনের অংশগুলি স্থির রাখুন এবং অ্যারে ব্যবহার করুন এটির একটি অংশ, বিকল্প বা ফাইলের নাম পূরণ করুন:
options=(-x -v)
files=(file1 "file name with whitespace")
target=/somedir
transmutate "${options[@]}" "${files[@]}" "$target"
অ্যারেগুলির ক্ষতিটি হ'ল এগুলি কোনও স্ট্যান্ডার্ড বৈশিষ্ট্য নয়, সুতরাং সরল পসিক্স শেলগুলি (যেমন ডিবিয়ান / উবুন্টুতে dash
ডিফল্ট /bin/sh
) তাদের সমর্থন করে না (তবে নীচে দেখুন)। বাশ, ksh এবং zsh করবেন, তবে এটি সম্ভবত আপনার সিস্টেমে কিছু শেল রয়েছে যা অ্যারে সমর্থন করে।
ব্যবহার "$@"
নামযুক্ত অ্যারেগুলির কোনও সমর্থন ছাড়াই শেলগুলিতে, "$@"
কমান্ডের আর্গুমেন্টগুলি ধরে রাখার জন্য এখনও কেউ অবস্থানীয় পরামিতিগুলি (সিউডো-অ্যারে ) ব্যবহার করতে পারে।
নিম্নলিখিতটি পোর্টেবল স্ক্রিপ্ট বিটগুলি হওয়া উচিত যা পূর্ববর্তী বিভাগে কোড বিটের সমতুল্য হয়। অ্যারের সাথে প্রতিস্থাপিত হয় "$@"
, অবস্থানগত পরামিতিগুলির তালিকা। সেটিংটি "$@"
সম্পন্ন করা হয় set
এবং চারপাশে ডাবল উদ্ধৃতিগুলি "$@"
গুরুত্বপূর্ণ (এগুলি তালিকার উপাদানগুলিকে স্বতন্ত্রভাবে উদ্ধৃত করার কারণ হিসাবে)।
প্রথমে একটি কমান্ড সংরক্ষণ করে আর্গুমেন্ট যুক্ত করে "$@"
এটি চালানো:
set -- ls -l "/tmp/test/my dir"
"$@"
শর্তাধীনভাবে কমান্ডের জন্য কমান্ড লাইন বিকল্পের অংশগুলি সেট করা:
set -- ls
if [ "$want_detail" = 1 ]; then
set -- "$@" -l
fi
set -- "$@" "$targetdir"
"$@"
শুধুমাত্র "$@"
বিকল্প এবং অপারেশনগুলির জন্য ব্যবহার :
set -- -x -v
set -- "$@" file1 "file name with whitespace"
set -- "$@" /somedir
transmutate "$@"
(অবশ্যই, "$@"
সাধারণত স্ক্রিপ্টে যুক্তি দিয়ে ভরা থাকে, তাই আপনাকে পুনরায় ধারণা দেওয়ার আগে সেগুলি কোথাও সংরক্ষণ করতে হবে "$@"
))
সাবধান eval
!
হিসাবে eval
প্রবর্তন উদ্ধৃতি ও সম্প্রসারণ প্রক্রিয়াকরণ একটি অতিরিক্ত স্তর, আপনি ব্যবহারকারীর ইনপুট সঙ্গে সতর্কতা অবলম্বন করা প্রয়োজন। উদাহরণস্বরূপ, এটি ততক্ষণ কাজ করে যতক্ষণ না ব্যবহারকারী কোনও একক উদ্ধৃতিতে টাইপ না করে:
read -r filename
cmd="ls -l '$filename'"
eval "$cmd";
তবে যদি তারা ইনপুট দেয় '$(uname)'.txt
, আপনার স্ক্রিপ্টটি আনন্দের সাথে কমান্ড প্রতিস্থাপন চালায়।
অ্যারে সহ একটি সংস্করণ এ থেকে অনাক্রম্য যেহেতু শব্দগুলি পুরো সময়ের জন্য পৃথক রাখা হয়, সুতরাং সামগ্রীর সামগ্রীর জন্য কোনও উদ্ধৃতি বা অন্য প্রক্রিয়াজাতকরণ নেই filename
।
read -r filename
cmd=(ls -ld -- "$filename")
"${cmd[@]}"
তথ্যসূত্র