আমি কেবল একটি ভেরিয়েবল বরাদ্দ করেছি, তবে প্রতিধ্বনি $ ভেরিয়েবল অন্য কিছু দেখায়


109

এখানে এমন কয়েকটি সিরিজের মামলা রয়েছে যেখানে echo $varসুনির্দিষ্টভাবে দেওয়া হয়েছে তার চেয়ে আলাদা মান দেখাতে পারে। নির্ধারিত মানটি "ডাবল কোটড", 'সিঙ্গল কোটড' বা অব্যর্থিত কিনা তা বিবেচনা না করেই এটি ঘটে।

আমার ভেরিয়েবলটি সঠিকভাবে সেট করতে আমি কীভাবে শেল পাব?

তারকাচিহ্ন

প্রত্যাশিত আউটপুটটি /* Foobar is free software */, তবে পরিবর্তে আমি ফাইলের নামের একটি তালিকা পাই:

$ var="/* Foobar is free software */"
$ echo $var 
/bin /boot /dev /etc /home /initrd.img /lib /lib64 /media /mnt /opt /proc ...

চতুস্কন বন্ধনী

প্রত্যাশিত মানটি হয় [a-z]তবে আমি কখনও কখনও তার পরিবর্তে একটি চিঠি পাই!

$ var=[a-z]
$ echo $var
c

লাইন ফিডস (নিউলাইনস)

প্রত্যাশিত মানটি পৃথক লাইনের এএ তালিকা, তবে পরিবর্তে সমস্ত মান এক লাইনে থাকে!

$ cat file
foo
bar
baz

$ var=$(cat file)
$ echo $var
foo bar baz

একাধিক স্পেস

আমি সাবধানে সারিবদ্ধভাবে টেবিল শিরোনাম প্রত্যাশা করেছি, তবে পরিবর্তে একাধিক স্পেস হয় অদৃশ্য হয়ে যায় বা একটিতে ভেঙে যায়!

$ var="       title     |    count"
$ echo $var
title | count

ট্যাব

আমি দুটি ট্যাব দ্বারা বিভাজিত মান প্রত্যাশা করেছি, তবে পরিবর্তে দুটি স্থান পৃথক মান পেয়েছি!

$ var=$'key\tvalue'
$ echo $var
key value

4
এটি করার জন্য ধন্যবাদ। আমি প্রায়শই লাইনটি ফিডের মুখোমুখি হই। তাই var=$(cat file)ঠিক আছে, কিন্তু echo "$var"প্রয়োজন।
০১:০7 এ

4
বিটিডাব্লু, এটিও বাশপিটস # 14: mywiki.wooledge.org/BashPitfalls#echo_.24foo
চার্লস ডাফি


এছাড়াও, তাও দেখতে stackoverflow.com/questions/2414150/...
tripleee

উত্তর:


148

উপরের সমস্ত ক্ষেত্রে ভেরিয়েবলটি সঠিকভাবে সেট করা হয়েছে তবে সঠিকভাবে পড়া হয়নি! সঠিক উপায় হ'ল রেফারেন্স দেওয়ার সময় ডাবল উক্তি ব্যবহার করা :

echo "$var"

এটি প্রদত্ত সমস্ত উদাহরণগুলিতে প্রত্যাশিত মান দেয়। সর্বদা উদ্ধৃতি পরিবর্তনশীল রেফারেন্স!


কেন?

যখন কোনও ভেরিয়েবলটি উদ্ধৃত হয় না , এটি হবে:

  1. ভুগা ক্ষেত্র বিভাজন যেখানে মান (ডিফল্ট অনুসারে) হোয়াইটস্পেস একাধিক শব্দ বিভক্ত হয়:

    আগে: /* Foobar is free software */

    পরে: /*, Foobar, is, free, software,*/

  2. এই শব্দের প্রত্যেকটিতেই পথের নাম প্রসার ঘটবে , যেখানে নিদর্শনগুলি মেলানো ফাইলগুলিতে প্রসারিত হয়:

    আগে: /*

    পরে: /bin, /boot, /dev, /etc, /home, ...

  3. পরিশেষে, সমস্ত আর্গুমেন্টগুলি প্রতিধ্বনিত হয়ে যায়, যা তাদের লেখায় একক ফাঁক দিয়ে আলাদা করে দেয়

    /bin /boot /dev /etc /home Foobar is free software Desktop/ Downloads/
    

    পরিবর্তে ভেরিয়েবলের মান।

যখন ভেরিয়েবল উদ্ধৃত হয় তা হবে:

  1. এর মান জন্য প্রতিস্থাপিত হতে হবে।
  2. কোনও পদক্ষেপ 2 নেই।

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


এটি সবসময় কাজ করে না আমি একটি উদাহরণ দিতে পারি: paste.ubuntu.com/p/8RjR6CS668
রেকলিক

4
হ্যাঁ, $(..)রেখাচিত্রমালা পিছনে স্ট্রিপস। আপনি var=$(cat file; printf x); var="${var%x}"এটি চারপাশে কাজ করতে ব্যবহার করতে পারেন ।
সেই অন্য লোকটি

19

কেন এটি হচ্ছে তা আপনি জানতে চাইতে পারেন। একসাথে সঙ্গে যে অন্যান্য লোক দ্বারা মহান ব্যাখ্যা , খুঁজুন একটি রেফারেন্স কেন হোয়াইটস্পেস বা অন্যান্য বিশেষ অক্ষর উপর আমার শেল স্ক্রিপ্ট চোক করে? দ্বারা লিখিত গিলেজ মধ্যে ইউনিক্স ও লিনাক্স :

আমার লেখার দরকার কেন "$foo"? উদ্ধৃতি ছাড়া কী হয়?

$foo"ভেরিয়েবলের মান নেওয়া" এর অর্থ এই নয় foo। এর অর্থ আরও জটিল কিছু:

  • প্রথমে ভেরিয়েবলের মান নিন।
  • ক্ষেত্র বিভাজন: সেই মানটিকে একটি সাদা ক্ষেত্র-বিচ্ছিন্ন ক্ষেত্রের তালিকা হিসাবে বিবেচনা করুন এবং ফলাফলটি তৈরি করুন। উদাহরণস্বরূপ, পরিবর্তনশীল থাকে foo * bar ​তাহলে এই পদক্ষেপ ফল 3-উপাদান তালিকা foo, *, bar
  • ফাইলের নাম জেনারেশন: প্রতিটি ক্ষেত্রকে গ্লোব হিসাবে বিবেচনা করুন, অর্থাৎ ওয়াইল্ডকার্ড প্যাটার্ন হিসাবে, এবং এই প্যাটার্নের সাথে মেলে এমন ফাইলের নামের সাথে এটি প্রতিস্থাপন করুন। যদি প্যাটার্নটি কোনও ফাইলের সাথে মেলে না, তবে এটি অশোধিত ছেড়ে দেওয়া হবে। আমাদের উদাহরণস্বরূপ, fooবর্তমান ডিরেক্টরিতে ফাইলগুলির তালিকা অনুসরণ করে এবং শেষ পর্যন্ত এই ফলাফলের ফলাফল রয়েছে bar। তাহলে বর্তমান ডিরেক্টরী খালি থাকে, ফল foo, *, bar

নোট করুন যে ফলাফলটি স্ট্রিংগুলির একটি তালিকা। শেল সিনট্যাক্সে দুটি কনটেক্সট রয়েছে: তালিকা প্রসঙ্গে এবং স্ট্রিং প্রসঙ্গে। ফিল্ড বিভাজন এবং ফাইলের নাম উত্পাদন কেবল তালিকার প্রসঙ্গেই ঘটে তবে বেশিরভাগ সময় এটিই ঘটে। ডাবল উদ্ধৃতিগুলি একটি স্ট্রিং প্রসঙ্গে সীমিত করুন: পুরো ডাবল-কোটেড স্ট্রিংটি একটি একক স্ট্রিং, বিভক্ত হওয়ার জন্য নয়। (ব্যতিক্রম: "$@"অবস্থানগত প্যারামিটারগুলির তালিকায় প্রসারণ করা, যেমন তিনটি অবস্থানগত পরামিতি "$@"সমতুল্য "$1" "$2" "$3"See * এবং $ @ এর মধ্যে পার্থক্য দেখুন কি? )

একই সঙ্গে কমান্ড প্রতিকল্পন ঘটবে $(foo)বা `foo`। সাইড নোটে, ব্যবহার করবেন না `foo`: এর উদ্ধৃতি বিধিগুলি অদ্ভুত এবং অ-বহনযোগ্য এবং সমস্ত আধুনিক শেল সমর্থন করে $(foo)যা স্বজ্ঞাত উদ্ধৃতি বিধি ব্যতীত একেবারে সমতুল্য।

পাটিগণিত প্রতিস্থাপনের আউটপুটও একই বিস্তৃতি বহন করে, তবে এটি সাধারণত উদ্বেগের বিষয় নয় কারণ এতে কেবল অ-প্রসারণযোগ্য অক্ষর রয়েছে (ধরে নেওয়া যায় IFSযে সংখ্যাসঙ্গি নেই বা আছে -)।

দেখুন কখন ডাবল-কোটিং দরকার? মামলাগুলি সম্পর্কে আরও বিশদের জন্য যখন আপনি উদ্ধৃতিগুলি ছাড়তে পারেন।

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


7

উদ্ধৃতি ব্যর্থ হওয়ার কারণে সৃষ্ট অন্যান্য সমস্যা ছাড়াও, -nএবং যুক্তি হিসাবে -eগ্রাস করা যেতে পারে echo। (কেবলমাত্র পসিক্স স্পেক অনুযায়ী প্রাক্তনই বৈধ echo, তবে বেশ কয়েকটি সাধারণ বাস্তবায়ন সেই অনুমানটিকে লঙ্ঘন করে এবং গ্রাসও করে -e)।

এটি এড়াতে, বিশদ বিবেচনা করার printfপরিবর্তে ব্যবহার echoকরুন।

এইভাবে:

$ vars="-e -n -a"
$ echo $vars      # breaks because -e and -n can be treated as arguments to echo
-a
$ echo "$vars"
-e -n -a

তবে, সঠিক উদ্ধৃতি সর্বদা আপনাকে সংরক্ষণ করবে না ব্যবহার করার সময় echo:

$ vars="-n"
$ echo $vars
$ ## not even an empty line was printed

... যদিও এটি আপনাকে এতে রক্ষা করবে printf:

$ vars="-n"
$ printf '%s\n' "$vars"
-n

হ্যাঁ, এর জন্য আমাদের একটি ভাল ছাড় দরকার! আমি সম্মত হলাম এটি প্রশ্নের শিরোনাম ফিট করে তবে আমি মনে করি না যে এটি এখানে প্রযোজ্য দৃশ্যমানতা পাবে। কীভাবে একটি নতুন প্রশ্ন - লা "আমার -e/ -n/ ব্যাকস্ল্যাশটি কেন প্রদর্শিত হচ্ছে না?" আমরা যথাযথ হিসাবে এখান থেকে লিঙ্ক যোগ করতে পারেন।
সে অন্য লোক

আপনি কি পাশাপাশি গ্রাস-n করতে চেয়েছিলেন ?
পেসা দ্য

4
@ পেসা, না, আমি বলতে চাইছি -e। মানটি echoআউটপুট নির্দিষ্ট করে না যখন তার প্রথম যুক্তিটি হয় -n, সেই ক্ষেত্রে কোনও / সমস্ত সম্ভাব্য আউটপুট আইনী করে তোলে; এর জন্য এ জাতীয় কোনও বিধান নেই -e
চার্লস ডাফি

ওহ ... আমি পড়তে পারি না এর জন্য আমার ইংরেজিকে দোষ দেওয়া যাক। ব্যাখ্যার জন্য ধন্যবাদ.
PesaThe


2

echo $varআউটপুট অত্যন্ত IFSপরিবর্তনশীল এর মান উপর নির্ভর করে । ডিফল্টরূপে এটিতে স্থান, ট্যাব এবং নিউলাইন অক্ষর রয়েছে:

[ks@localhost ~]$ echo -n "$IFS" | cat -vte
 ^I$

এর অর্থ হ'ল শেল যখন ক্ষেত্র বিভাজন (বা শব্দ বিভাজন) করছে তখন শব্দটি পৃথককারী হিসাবে এই সমস্ত অক্ষর ব্যবহার করে। এটি প্রতিধ্বনিত করতে ডাবল উদ্ধৃতি ব্যতীত কোনও ভেরিয়েবলকে উল্লেখ করে ( $var) এবং সুতরাং প্রত্যাশিত আউটপুট পরিবর্তন করা হয়।

শব্দের বিভাজন রোধ করার একটি উপায় (ডাবল উদ্ধৃতি ব্যবহার করা) IFSশূন্যে সেট করা। Http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_05 দেখুন :

যদি আইএফএসের মান নাল হয় তবে কোনও ফিল্ড বিভাজন করা হবে না।

নালায় সেট করার অর্থ শূন্য মানটিতে সেট করা:

IFS=

পরীক্ষা:

[ks@localhost ~]$ echo -n "$IFS" | cat -vte
 ^I$
[ks@localhost ~]$ var=$'key\nvalue'
[ks@localhost ~]$ echo $var
key value
[ks@localhost ~]$ IFS=
[ks@localhost ~]$ echo $var
key
value
[ks@localhost ~]$ 

4
আপনাকে set -fগ্লোবালিং প্রতিরোধ করতে হবে
অন্য

@ থ্যাথথেরগুই, পথ প্রসারণ সহ আপনার 1 ম উদাহরণের জন্য এটি কি সত্যিই প্রয়োজনীয়? সঙ্গে IFSনাল সেট করতে চান, echo $varসম্প্রসারিত করা হবে echo '/* Foobar is free software */'এবং পথ সম্প্রসারণ একক উদ্ধৃতিচিহ্ন সহ পংক্তি ভিতরে সঞ্চালিত হয় না।
ks1322

4
হ্যাঁ. যদি আপনি mkdir "/this thing called Foobar is free software etc/"দেখতে পান যে এটি এখনও প্রসারিত হয়েছে। [a-z]উদাহরণস্বরূপ এটি অবশ্যই আরও ব্যবহারিক practical
সে অন্য লোক

আমি দেখতে পাচ্ছি, [a-z]উদাহরণস্বরূপ এটি উপলব্ধি করে ।
ks1322

2

Ks1322 এর উত্তর আমাকে ব্যবহার করার সময় সমস্যাটি সনাক্ত করতে সহায়তা করেছিল docker-compose exec:

আপনি যদি -Tপতাকাটি বাদ দেন , docker-compose execএকটি বিশেষ অক্ষর যুক্ত করুন যা আউটপুট ভঙ্গ করে, আমরা এর bপরিবর্তে দেখতে পেলাম 1b:

$ test=$(/usr/local/bin/docker-compose exec db bash -c "echo 1")
$ echo "${test}b"
b
echo "${test}" | cat -vte
1^M$

সঙ্গে -Tপতাকা, docker-compose execযেমন প্রত্যাশিত কাজ করে:

$ test=$(/usr/local/bin/docker-compose exec -T db bash -c "echo 1")
$ echo "${test}b"
1b

-2

উদ্ধৃতিতে ভেরিয়েবলটি যুক্ত করার পাশাপাশি, trস্পেসগুলি নতুন লাইনে রূপান্তর করে এবং ভেরিয়েবলের আউটপুট অনুবাদ করতে পারে ।

$ echo $var | tr " " "\n"
foo
bar
baz

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


4
তবে এটি সমস্ত স্থানকে নতুন লাইনের প্রতিস্থাপন করে । উদ্ধৃতি বিদ্যমান নিউলাইন এবং স্পেস সংরক্ষণ করে।
ব্যবহারকারী000001

সত্য, হ্যাঁ আমি মনে করি এটি ভেরিয়েবলের মধ্যে কী রয়েছে তার উপর নির্ভর করে। আমি trটেক্সট ফাইলগুলি থেকে অ্যারে তৈরি করতে প্রায় অন্য উপায়ে ব্যবহার করি ।
আলেক

4
ভেরিয়েবলটি সঠিকভাবে উদ্ধৃত না করে একটি সমস্যা তৈরি করা এবং তারপরে হ্যামস্টেস্টড অতিরিক্ত প্রক্রিয়া নিয়ে কাজ করা ভাল প্রোগ্রামিং নয়।
ট্রিপলি

@ আলেক, ... ভুল, কী? কোনও trপাঠ্য ফাইল থেকে সঠিকভাবে / সঠিকভাবে অ্যারে তৈরি করার দরকার নেই - আপনি আইএফএস সেট করে যা কিছু বিচ্ছিন্ন করতে চান তা নির্দিষ্ট করতে পারেন। উদাহরণস্বরূপ: IFS=$'\n' read -r -d '' -a arrayname < <(cat file.txt && printf '\0')ব্যাশ ৩.২ (বিস্তৃত সঞ্চালনের প্রাচীনতম সংস্করণ) এর মাধ্যমে সমস্ত পথে কাজ করে এবং আপনার catব্যর্থ হলে সঠিকভাবে প্রস্থান স্থিতিকে মিথ্যাতে সেট করে । এবং আপনি যদি নতুন লাইনের পরিবর্তে ট্যাবগুলি বলতে চান, আপনি কেবল এটির $'\n'সাথে প্রতিস্থাপন করতে পারেন $'\t'
চার্লস ডাফি

4
@ আলেক, ... আপনি যদি এমন কিছু করেন arrayname=( $( cat file | tr '\n' ' ' ) )তবে তা একাধিক স্তরের উপর ভেঙে পড়ে: এটি আপনার ফলাফলকে গ্রাবিং করছে (সুতরাং *বর্তমান ডিরেক্টরিতে ফাইলগুলির তালিকায় পরিণত হয়), এবং এটি ছাড়াও এটি কার্যকর হবেtr ( বা cat, এই বিষয়ে; কেউ কেবল ব্যবহার করতে পারে arrayname=$( $(<file) )এবং এটি একই পদ্ধতিতে ভেঙে দেওয়া হবে, তবে অদক্ষভাবে কম)।
চার্লস ডাফি 21
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.