একটি উদ্ধৃত ভেরিয়েবলের বিকল্পগুলি কেন ব্যর্থ হয়, তবে অব্যক্ত অবস্থায় কাজ করে?


18

আমি পড়লাম যে আমার বাশগুলিতে ভেরিয়েবলগুলি উদ্ধৃত করা উচিত, যেমন $ foo এর পরিবর্তে "$ foo"। তবে, স্ক্রিপ্ট লেখার সময়, আমি একটি কেস পেয়েছি যেখানে এটি উদ্ধৃতি ছাড়া কাজ করে তবে তাদের সাথে নয়:

wget_options='--mirror --no-host-directories'
local_root="$1" # ./testdir recieved from command line
remote_root="$2" # ftp://XXX recieved from command line 
relative_path="$3" # /XXX received from command line

এই এক কাজ করে:

wget $wget_options --directory_prefix="$local_root" "$remote_root$relative_path"

এটির কোনওটি নেই (ডাবল কোটস অরং $ wget_options নোট করুন):

wget "$wget_options" --directory_prefix="$local_root" "$remote_root$relative_path"
  • এটার কারণ কি?

  • প্রথম লাইনটি ভাল সংস্করণ; বা আমার সন্দেহ করা উচিত যে কোথাও কোনও লুকানো ত্রুটি রয়েছে যা এই আচরণের কারণ হয়ে দাঁড়ায়?

  • সাধারণভাবে, ব্যাশ এবং এর উদ্ধৃতিগুলি কীভাবে কাজ করে তা বোঝার জন্য আমি কোথায় ভাল ডকুমেন্টেশন পাই? এই স্ক্রিপ্টটি লেখার সময় আমার মনে হয় যে আমি নিয়মগুলি বোঝার পরিবর্তে একটি ট্রায়াল-এন্ড-ত্রুটির ভিত্তিতে কাজ শুরু করেছি।


3
আপনার প্রশ্নের উত্তর এখানে দেওয়া হয়েছে: mywiki.wooledge.org/BashFAQ/050
গ্লেন জ্যাকম্যান

3
নিয়মগুলির জন্য উত্সটিতে যান: বাশ ম্যানুয়াল । 3.5 বিভাগ "শেল সম্প্রসারণ", বিশেষত শব্দ বিভাজন এবং ফাইলের নাম সম্প্রসারণের দিকে মনোযোগ দিন - এই 2 কারণগুলি আপনি নিয়ন্ত্রণ করতে কোট ব্যবহার করেন।
গ্লেন জ্যাকম্যান


4
আমি মনে করি এটি কমান্ড লাইন আর্গুমেন্টগুলি কীভাবে নিম্ন স্তরে কাজ করে তা বুঝতে সহায়তা করে। যখন একটি প্রোগ্রাম কার্যকর করা হয়, এটি অক্ষরের তালিকাগুলির তালিকা হিসাবে যথেষ্ট পরিমাণে ঘনিষ্ঠ হয়ে যুক্তিগুলি গ্রহণ করে। প্রতিটি অভ্যন্তরীণ তালিকা হ'ল আমরা একটি "যুক্তি" বলি। বেশিরভাগ প্রোগ্রামগুলি অর্গগুলির মধ্যে যৌক্তিক পৃথকীকরণের উপর নির্ভর করে। এখানে, আপনি দেখতে পাচ্ছেন যে (কী হিসাবে একটি যুক্তি হিসাবে) এর অর্থ wgetজানেন না --mirror --no-host-directories, তবে এটি দুটি আর্গুমেন্টে বিভক্ত হয়ে গেলে এটি পরিচালনা করে । যুক্তি ভেক্টরের অভ্যন্তরে খুব কম প্রোগ্রামগুলি স্পেস এবং কোটগুলি বিশেষভাবে ব্যবহার করে। সমস্যাটি হ'ল bash, এবং অন্যান্য শেলগুলি বোঝানো হচ্ছে>
HTNW

2
> মানুষের দ্বারা ব্যবহৃত। এটি আর্গুমেন্টের মধ্যে সীমাটি ম্যানুয়ালি সংজ্ঞায়িত করতে বিরক্তিকর হবে, সুতরাং শাঁসগুলি একটি লাইনকে (অক্ষরের একটি তালিকা) আর্গুমেন্ট ভেক্টর (চরিত্রের তালিকাগুলির তালিকা) রূপান্তর করার জন্য শ্বেত স্পেসে বিভক্ত হয়। পরিবর্তনীয় সম্প্রসারণ হ'ল প্রথম বিস্তৃতি bash, সুতরাং আপনি কল্পনা করতে পারেন যে $aএটি সরাসরি তার বিষয়বস্তু লেখার সমতুল্য। এখন বিষয়টি স্পষ্ট: a="-a -b"; cmd "$a"প্রসারিত হয়েছে cmd "-a -b", তবে cmdসম্ভবত এর অর্থ কী তা জানেন না। cmd $aবিস্তৃতি cmd -a -b, যা সম্ভবত না হবে।
এইচটিএনডাব্লু

উত্তর:


28

মূলত, শব্দ বিভাজন (এবং ফাইলের নাম উত্পাদন) থেকে তাদের রক্ষা করতে আপনার পরিবর্তনশীল বিস্তৃতি দ্বিগুণ করা উচিত। তবে, আপনার উদাহরণে,

wget_options='--mirror --no-host-directories'
wget $wget_options --directory_prefix="$local_root" "$remote_root$relative_path"

শব্দ বিভাজন ঠিক আপনি চান কি

সঙ্গে "$wget_options"(উদ্ধৃত), wgetকি একক যুক্তি দিয়ে কি করতে জানে না --mirror --no-host-directoriesএবং অভিযোগ

wget: unknown option -- mirror --no-host-directories

জন্য wgetদুটি বিকল্প দেখতে --mirrorএবং --no-host-directoriesহিসাবে পৃথক, শব্দ বিভাজন ঘটতে হয়েছে।

এটি করার আরও শক্তিশালী উপায় রয়েছে। আপনি যদি ব্যবহার করছেন bashবা অন্য কোনও শেল যা bashকরণীয় যেমন অ্যারে ব্যবহার করে তবে গ্লেন জ্যাকম্যানের উত্তর দেখুনগিলসের উত্তরটি স্ট্যান্ডার্ডের মতো প্লেয়ার শেলগুলির বিকল্প বিকল্পও বর্ণনা করে /bin/sh। উভয়ই মূলত প্রতিটি বিকল্পকে একটি অ্যারেতে আলাদা উপাদান হিসাবে সঞ্চয় করে।

ভাল উত্তরের সাথে সম্পর্কিত প্রশ্ন: আমার শেল স্ক্রিপ্টটি সাদা স্থান বা অন্যান্য বিশেষ চরিত্রগুলিতে কেন দম বন্ধ করে দেয়?


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

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

variable=$other_variable

আরেকটি হ'ল

case $variable in
    ...) ... ;;
esac

2
এই বিভাজন + গ্লোব অপারেটরটি ব্যবহার করার আগে, কোনওটির অবশ্যই $IFSসঠিক মান রয়েছে তা নিশ্চিত করা দরকার । এখানে আপনাকে স্পেসে বিভক্ত করতে হবে এবং পাঠ্যটি কোনও ট্যাব বা নতুনলাইন ধারণ করে না, সুতরাং এর ডিফল্ট মানটি $IFSকরতে হবে তবে যদি সেই কোডটি এমন কোনও ফাংশনটিতে ব্যবহার করতে হয় যেখানে একটি প্রসঙ্গে বলা যেতে পারে যেখানে $IFSসংশোধন করা যেতে পারে , আপনি $IFSআগেই সেট করতে চান (এবং সম্ভবত এটির পরে পুনরুদ্ধার করুন বা যদি বাকী কোডটি একটি $IFS
অশোধিত রূপ

32

কোডের সবচেয়ে শক্তিশালী উপায় যা অ্যারে ব্যবহার করা হয়:

wget_options=(
    --mirror 
    --no-host-directories
    --directory_prefix="$1"
)
wget "${wget_options[@]}" "$2/$3"

এটি সঠিক উত্তর। তথ্যসূত্র
l0b0

2
এটি একটি উত্তরের উত্তর, তাই আমি এটিকে উজ্জীবিত করেছি তবে কুসালান্দা কেন আমাকে আমার কোডটি ভুল বলে বুঝতে সাহায্য করেছিল এবং আমি কেবল একটি গ্রহণ করতে পারি।
z32a7ul

আরএসসিএনসি তালিকার কেউ আমাকে এই নির্মাণ দেখানো না হওয়া পর্যন্ত আমি সমস্যার জগতে ডুবে ছিলাম। এটি বিশেষত সহায়ক যদি কিছু উপাদান খালি স্ট্রিং হতে পারে। এটি খালি স্ট্রিংগুলি অদৃশ্য করে তোলে। কিছু আদেশ কমান্ড পছন্দ করে cpএবং rsyncঅপ্রত্যাশিত জিনিসগুলি করে যদি আপনার কমান্ড এর মতো কিছুতে প্রসারিত হয় rsync '' rest of parameters। শর্তসাপেক্ষে কমান্ড টুকরো টুকরো টুকরো করে এটি এক জায়গায় একবার চালানোর জন্য দুর্দান্ত।
জো

17

আপনি স্ট্রিং ভেরিয়েবলের স্ট্রিংগুলির একটি তালিকা সঞ্চয় করার চেষ্টা করছেন। এটি ফিট করে না। আপনি কীভাবে ভেরিয়েবলটি অ্যাক্সেস করেন না কেন, কিছু নষ্ট হয়ে যায়।

wget_options='--mirror --no-host-directories'ভেরিয়েবলটিকে wget_optionsএকটি স্ট্রিংয়ে সেট করে যা একটি স্থান রাখে। এই মুহুর্তে, স্থানটি কোনও বিকল্পের অংশ বা বিকল্পগুলির মধ্যে বিভাজক হিসাবে বিবেচিত হবে কিনা তা জানার কোনও উপায় নেই।

আপনি যখন কোনও উদ্ধৃত প্রতিস্থাপনের সাহায্যে ভেরিয়েবল অ্যাক্সেস করেন তখন ভেরিয়েবলের wget "$wget_options"মান স্ট্রিং হিসাবে ব্যবহৃত হয়। এর অর্থ এটি একটি একক পরামিতি হিসাবে পাস হয়েছে wget, সুতরাং এটি একটি একক বিকল্প। এটি আপনার ক্ষেত্রে বিরতি কারণ আপনি এটি একাধিক বিকল্প বোঝাতে চেয়েছিলেন।

আপনি যখন অকেজো প্রতিস্থাপন ব্যবহার wget $wget_optionsকরেন, তখন স্ট্রিং ভেরিয়েবলের মান "স্প্লিট + গ্লোব" ডাকনামযুক্ত একটি প্রসারণ প্রক্রিয়াটি অতিক্রম করে:

  1. ভেরিয়েবলের মানটি ধরুন এবং এটিকে সাদা স্থান-সীমিত অংশে বিভক্ত করুন (ধরে নিবেন আপনি $IFSভেরিয়েবলটি পরিবর্তন করেননি )। এটি স্ট্রিংগুলির একটি মধ্যবর্তী তালিকার ফলস্বরূপ।
  2. মধ্যবর্তী তালিকার প্রতিটি উপাদানগুলির জন্য, যদি এটি একটি ওয়াইল্ডকার্ড প্যাটার্ন হয় যা এক বা একাধিক ফাইলের সাথে মেলে, তবে সেই উপাদানটি ম্যাচের ফাইলগুলির তালিকায় প্রতিস্থাপন করুন।

এটি আপনার উদাহরণে কাজ করার জন্য ঘটে কারণ বিভাজন প্রক্রিয়াটি স্থানটিকে পৃথককারী হিসাবে রূপান্তর করে তবে সাধারণভাবে কাজ করে না কারণ কোনও বিকল্পে ফাঁকা স্থান এবং ওয়াইল্ডকার্ডের অক্ষর থাকতে পারে।

Ksh, bash, yash এবং zsh এ আপনি একটি অ্যারে ভেরিয়েবল ব্যবহার করতে পারেন। শেল পরিভাষায় একটি অ্যারে হল স্ট্রিংগুলির তালিকা, সুতরাং কোনও তথ্যের ক্ষতি হয় না। একটি অ্যারে ভেরিয়েবল তৈরি করতে, ভেরিয়েবলের মান নির্ধারণের সময় অ্যারে উপাদানগুলির চারপাশে বন্ধনী রাখুন। অ্যারের সমস্ত উপাদান অ্যাক্সেস করতে, ব্যবহার করুন - এটি একটি সাধারণীকরণ , যা অ্যারের উপাদানগুলি থেকে একটি তালিকা গঠন করে। নোট করুন যে আপনার এখানেও ডাবল উদ্ধৃতি প্রয়োজন, অন্যথায় প্রতিটি উপাদান বিভাজন + গ্লোব সহকারে চলেছে।"${VARIABLE[@]}""$@"

wget_options=(--mirror --no-host-directories --user-agent="I can haz spaces")
wget "${wget_options[@]}" 

সরল sh এ, কোনও অ্যারে ভেরিয়েবল নেই। যদি আপনি অবস্থানগত আর্গুমেন্টগুলি হারাতে আপত্তি না করেন তবে আপনি সেগুলি একটি স্ট্রিংয়ের তালিকা সঞ্চয় করতে ব্যবহার করতে পারেন।

set -- --mirror --no-host-directories --user-agent="I can haz spaces"
wget "$@" 

আরও তথ্যের জন্য, দেখুন কেন আমার শেল স্ক্রিপ্টটি সাদা স্থান বা অন্যান্য বিশেষ অক্ষরগুলিতে দম বন্ধ করে দেয়?


প্লেইন SH জন্য subshell অবস্থানগত আর্গুমেন্ট সংরক্ষণ হবে: (set -- ...; exec wget "$@" ...)
জন কুগেলম্যান
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.