প্রতিধ্বনির জন্য নয়, কেন আমাকে ভেরিয়েবলের উদ্ধৃতি দিতে হবে?


26

আমি পড়েছি আপনার ভেরিয়েবলগুলি প্রসারণের জন্য ডাবল উদ্ধৃতি প্রয়োজন

if [ -n "$test" ]; then echo '$test ok'; else echo '$test null'; fi

প্রত্যাশিত হিসাবে কাজ করবে, যখন

if [ -n $test ]; then echo '$test ok'; else echo '$test null'; fi

নাল $test okহলেও সর্বদা বলবে $test

তবে আমাদের কেন কোট দরকার নেই echo $test?


2
আপনি যদি আরগ হিসাবে ব্যবহৃত ভেরিয়েবলটি উদ্ধৃত না করেন echo, অতিরিক্ত স্থান এবং নিউলাইনগুলি কেড়ে নেওয়া হবে।
জর্দানম

উত্তর:


36

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

তালিকা প্রেক্ষিতে মত সহজ কমান্ড আর্গুমেন্ট অন্তর্ভুক্ত [বা echo, for i in <here>, অ্যারে বরাদ্দকরণ ... অন্যান্য প্রসঙ্গে যেখানে ভেরিয়েবল এছাড়াও উদ্ধৃত করা প্রয়োজন আছে। আপনি যদি না চান খুব ভাল কারণ না পান তবে সর্বদা ভেরিয়েবলগুলি উদ্ধৃত করা সেরা।

বিভাজন + গ্লোব অপারেটর হিসাবে উদ্ধৃতিগুলির (তালিকা প্রসঙ্গে) অনুপস্থিতির কথা ভাবেন ।

যেন echo $testছিল echo glob(split("$test"))

শেল আচরণ অধিকাংশ লোক বিভ্রান্তিকর হয় কারণ অধিকাংশ অন্যান্য ভাষায়, আপনার চারপাশের স্ট্রিং সংশোধন মত কোট করা puts("foo"), এবং ভেরিয়েবল (যেমন প্রায় puts(var)) যখন শেল এটা অন্যান্য উপায় বৃত্তাকার আছে: সবকিছু শেল মধ্যে স্ট্রিং, তাই সবকিছু প্রায় কোট নির্বাণ কষ্টকর হবে, আপনার echo test, আপনার দরকার নেই "echo" "test"। শেল-এ, উদ্ধৃতিগুলি অন্য কোনও কিছুর জন্য ব্যবহৃত হয়: কিছু চরিত্রের বিশেষ অর্থ প্রতিরোধ করে এবং / অথবা কিছু বিস্তারের আচরণকে প্রভাবিত করে।

ইন [ -n $test ]বা echo $test, শেল বিভক্ত হবে $test(সমস্ত প্রসারিত (ডিফল্ট অনুসারে ঐ খালি উপর), এবং তারপর ফাইলের নাম প্রজন্ম সঞ্চালন *ম্যাচিং ফাইলগুলির তালিকার, '?' ... নিদর্শন), এবং তারপর আর্গুমেন্ট যে তালিকা পাস [বা echoকমান্ড ।

আবার, এটি হিসাবে ভাবেন "[" "-n" glob(split("$test")) "]"। যদি $testখালি থাকে বা কেবল ফাঁকা (এসপিসি, ট্যাব, এনএল) থাকে তবে স্প্লিট + গ্লোব অপারেটর একটি খালি তালিকা ফিরিয়ে দেবে, সুতরাং এটি [ -n $test ]হবে "[" "-n" "]", যা "-n" খালি পরীক্ষা করতে হবে এটি খালি স্ট্রিং কিনা। তবে ভাবুন যে $test"*" বা "= ফু" থাকলে কী হত ...

ইন [ -n "$test" ], [চার আর্গুমেন্ট পাস করা হয়েছে "[", "-n", ""এবং "]"(উদ্ধৃতিগুলি ছাড়াই), যা আমরা কি চাই।

এটি echoবা [কোনও পার্থক্য না ঘটায়, এটি echoখালি আর্গুমেন্ট বা কোনও যুক্তি কোনও ক্ষেত্রেই পাস করেছে কিনা তা কেবল একই জিনিসকে আউটপুট করে।

কমান্ড এবং কনস্ট্রাক্ট সম্পর্কিত আরও তথ্যের জন্য অনুরূপ প্রশ্নের এই উত্তরটিও দেখুন ।[[[...]]


7

@ h3rrmiller এর উত্তরটি আপনার if(বা বরং, [/ test) এর জন্য কোটগুলির প্রয়োজন কেন তা ব্যাখ্যা করার জন্য ভাল তবে আমি আসলে পোস্ট করব যে আপনার প্রশ্নটি ভুল।

নিম্নলিখিত কমান্ডগুলি ব্যবহার করে দেখুন এবং আমি কী বলতে চাইছি তা আপনি দেখতে পাবেন।

export testvar="123    456"
echo $testvar
echo "$testvar"

উদ্ধৃতিগুলি ছাড়াই, পরিবর্তনশীল প্রতিস্থাপনের ফলে দ্বিতীয় কমান্ডটি প্রসারিত হয়:

echo 123    456

এবং একাধিক স্পেসগুলি একককে ধসে গেছে:

echo 123 456

উদ্ধৃতি সহ, স্থানগুলি সংরক্ষণ করা হয়।

এই ঘটনা কারণ যখনই আপনি (যে পরামিতি পাস কিনা একটি প্যারামিটার উদ্ধৃত echo, testঅথবা অন্য কোনো কমান্ড), যে প্যারামিটারের মান হিসাবে পাঠানো হয় এক কমান্ডে মান। যদি আপনি এটিকে উদ্ধৃতি না দিয়ে থাকেন তবে প্রতিটি প্যারামিটারটি কোথায় শুরু হয় এবং শেষ হয় তা নির্ধারণের জন্য শেলটি সাদা জায়গার সন্ধান করার স্বাভাবিক যাদু করে।

এটি নিম্নলিখিত (খুব খুব সাধারণ) সি প্রোগ্রাম দ্বারা চিত্রিতও করা যেতে পারে। কমান্ড লাইনে নিম্নলিখিতটি চেষ্টা করুন (আপনি এটি কোনও খালি ডিরেক্টরিতে করতে চান যাতে কোনও কিছু ওভাররাইট করার ঝুঁকি না থাকে)।

cat <<EOF >paramtest.c
#include <stdio.h>
int main(int argc, char **argv) {
  int nparams = argc-1; /* because 1 parameter means only the executable's name */
  printf("%d parameters received\n", nparams);
  return nparams;
}
EOF
cc -o paramtest paramtest.c

এবং তারপর...

./paramtest 123 456
./paramtest "123 456"
./paramtest 123   456
./paramtest "123   456"

দৌড়ানোর পরে paramtest, $?এটি পাস হওয়া পরামিতিগুলির সংখ্যা ধরে রাখবে (এবং সেই নম্বরটি মুদ্রিত হবে)।


2

কোনও প্রোগ্রাম কার্যকর হওয়ার আগে শেল কীভাবে লাইনের ব্যাখ্যা করে তা এই সমস্ত ।

লাইন পড়লে echo I am $USER , শেলটি এটিকে প্রসারিত করে echo I am blrflএবং echoপাঠ্যের মূলটি আক্ষরিক বা পরিবর্তনশীল প্রসারিত কিনা তার কোনও ধারণা নেই। একইভাবে, যদি একটি লাইন পড়ে echo I am $UNDEFINED, শেলটি $UNDEFINEDকোনও কিছুর মধ্যে প্রসারিত হবে এবং প্রতিধ্বনিগুলির আর্গুমেন্টগুলি হবে I amএবং এটি এর শেষ। যেহেতু echoকোনও যুক্তি ছাড়াই ঠিক কাজ করে, echo $UNDEFINEDসম্পূর্ণ বৈধ।

আপনার সমস্যাটি ifআসলে সাথে নেইif , কারণ ifপ্রোগ্রাম এবং আর্গুমেন্ট যা অনুসরণ করে কেবল চালায় এবং thenপ্রোগ্রামটি বেরিয়ে 0গেলে elseঅংশটি কার্যকর করে (বা অংশটি যদি থাকে এবং প্রোগ্রামটি অ-উপস্থিত হয় 0):

if /bin/true ; then echo True dat. ; fi
if fgrep -q blrfl /etc/passwd ; then echo Blrfl has an account. ; fi

আপনি যখন if [ ... ]তুলনা করতে ব্যবহার করেন , আপনি শেলের মধ্যে নির্মিত আদিমগুলি ব্যবহার করছেন না। আপনি আসলে শেলটিকে একটি প্রোগ্রাম পরিচালিত করার জন্য নির্দেশ দিচ্ছেন [যা একটি অতি সামান্য সুপারসেট test(1)যার শেষ আর্গুমেন্ট হওয়া দরকার ]0পরীক্ষার শর্তটি 1যদি সত্য হয় এবং যদি তা না ঘটে তবে উভয় প্রোগ্রামই প্রস্থান করে ।

যখন কোনও ভেরিয়েবল অপরিজ্ঞাত হয় তখন কিছু পরীক্ষা ভাঙার কারণ এটি test আপনি ভেরিয়েবলটি ব্যবহার করছেন না তা দেখে। [ $UNDEFINED -eq 2 ]তবুও , বিরতি কারণ শেলটি এটির সাথে সম্পন্ন হওয়ার সাথে সাথে সমস্ত testআর্গুমেন্টই দেখায় -eq 2 ]যা কোনও বৈধ পরীক্ষা নয়। আপনি যদি এটি কোনও সংজ্ঞায়িত কিছু দিয়ে করেন [ $DEFINED -ne 0 ], যেমন , এটি কাজ করবে কারণ শেল এটি একটি বৈধ পরীক্ষায় (যেমন, 0 -ne 0) প্রসারণ করবে ।

এর মধ্যে একটি অর্থগত পার্থক্য রয়েছে foo $UNDEFINED bar, যা দুটি যুক্তি ( fooএবং bar) $UNDEFINEDপর্যন্ত প্রসারিত কারণ এটির নাম অবধি বেঁচে ছিল। এর সাথে তুলনা করুন foo "$UNDEFINED" bar, যা তিনটি আর্গুমেন্টে প্রসারিত (foo , একটি খালি স্ট্রিং এবং `বার) । উক্তি শেলকে তাদের মধ্যে কিছু আছে কি না তা যুক্তি হিসাবে ব্যাখ্যা করতে বাধ্য করে।


0

উক্তি ব্যতীত $test ব্যতীত একাধিক শব্দের আকারে প্রসারিত হতে পারে সুতরাং বাক্য গঠনটি ভাঙার জন্য এটি উদ্ধৃত করা প্রয়োজন যেহেতু [কমান্ডের অভ্যন্তরে প্রতিটি সুইচ একটি যুক্তি প্রত্যাশা করে যা কোটগুলি যা করে (যা $testএকটি যুক্তিতে প্রসারিত করে)

ভেরিয়েবলটি প্রসারিত করার জন্য আপনার যে উক্তিগুলির প্রয়োজন হবে না echo নেই কারণ এটি একটি যুক্তির প্রত্যাশা করে না। এটি কেবল আপনি যা বলবেন তা মুদ্রণ করবে। সুতরাং যদি $test100 শব্দের প্রতিধ্বনি প্রসারিত হয় তবে এটি প্রিন্ট করবে।

বাশ পিটফলস একবার দেখুন


হ্যাঁ তবে কেন আমাদের এটির দরকার নেই echo?
চার্লসবি

@ চার্লসবি আপনার জন্য উদ্ধৃতিগুলি দরকার echo। অন্যথায় আপনাকে কী ভাবায়?
গিলস

আমার তাদের দরকার নেই, আমিও echo $testএটি করতে পারি এবং এটি কাজ করে (এটি $ পরীক্ষার মান দেয়)
চার্লসবি

1
@ চারলেসবি এটি কেবলমাত্র পরীক্ষার মান আউটপুট করে যদি এতে কোথাও একাধিক স্পেস না থাকে। কারণটির উদাহরণের জন্য আমার উত্তরে প্রোগ্রামটি চেষ্টা করুন।
একটি সিভিএন

0

উদ্ধৃতি না দিলে খালি প্যারামিটারগুলি সরানো হয়:

start cmd:> strace -e trace=execve echo foo $bar baz
execve("/usr/bin/echo", ["echo", "foo", "baz"], [/* 100 vars */]) = 0

start cmd:> strace -e trace=execve echo foo "$bar" baz
execve("/usr/bin/echo", ["echo", "foo", "", "baz"], [/* 100 vars */]) = 0

ডাকা কমান্ডটি শেল কমান্ড লাইনে খালি প্যারামিটারটি দেখেনি। দেখে মনে হচ্ছে [অনুসরণযোগ্য কিছু হিসাবে -n এর জন্য 0 ফেরত সংজ্ঞায়িত করা হয়েছে। Whyever।

বেশ কয়েকটি ক্ষেত্রে উদ্ধৃতিও প্রতিধ্বনির জন্য একটি তাত্পর্য তৈরি করে:

var='*'
echo $var
echo "$var"

var="foo        bar"
echo $var
echo "$var"

2
এটি না echo, এটি খোল। আপনি একই আচরণ দেখতে পাবেন lstouch '*'আপনি দু: সাহসিক মনে হলে কিছু সময় চেষ্টা করুন । :)
একটি সিভিএন

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