“পড়ার সময়…” ব্যবহার করে ইকো এবং প্রিন্টফের বিভিন্ন ফলাফল পাওয়া যায়


14

"লিনাক্স স্ক্রিপ্টে " পড়ার সময় ... " এই প্রশ্নটি অনুসারে "

echo '1 2 3 4 5 6' | while read a b c;do echo "$a, $b, $c"; done

ফলাফল:

1, 2, 3 4 5 6

কিন্তু যখন আমি প্রতিস্থাপন echoসঙ্গেprintf

echo '1 2 3 4 5 6' | while read a b c ;do printf "%d, %d, %d \n" $a $b $c; done

ফলাফল

1, 2, 3
4, 5, 6

কেউ দয়া করে আমাকে বলতে পারেন যে এই দুটি আদেশ আরও আলাদা করে তোলে? ধন্যবাদ ~

উত্তর:


24

এটি শুধু প্রতি বনাম প্রিন্টফ নয়

প্রথমে, read a b cঅংশটি দিয়ে কী ঘটে তা বুঝতে দিন । ভেরিয়েবলের readডিফল্ট মানের উপর ভিত্তি করে শব্দ বিভাজন সম্পাদন করবে IFSযা স্পেস-ট্যাব-নতুনলাইন, এবং এর ভিত্তিতে সমস্ত কিছু ফিট করবে। ভেরিয়েবলগুলি ধরে রাখার জন্য যদি আরও ইনপুট থাকে তবে এটি বিভক্ত অংশগুলিকে প্রথম ভেরিয়েবলের সাথে ফিট করবে এবং যা ফিট করা যায় না - তা শেষের দিকে চলে যাবে। আমি যা বলতে চাইছি তা এখানে:

bash-4.3$ read a b c <<< "one two three four"
bash-4.3$ echo $a
one
bash-4.3$ echo $b
two
bash-4.3$ echo $c
three four

এটি ঠিক এভাবেই bashএর ম্যানুয়ালটিতে বর্ণিত হয়েছে (উত্তরের উদ্ধৃতিটি দেখুন)।

আপনার ক্ষেত্রে যা ঘটে তা হ'ল, 1 এবং 2 a এবং b ভেরিয়েবলের সাথে খাপ খায় এবং সি সমস্ত কিছু গ্রহণ করে যা হয় 3 4 5 6

আপনি যা অনেক সময় দেখতে পাবেন তা হ'ল লোকেরা while IFS= read -r line; do ... ; done < input.txtলাইন দিয়ে টেক্সট ফাইলগুলি পড়তে ব্যবহার করে। আবার IFS=শব্দ বিভাজন নিয়ন্ত্রণ করার কারণেই এখানে রয়েছে বা আরও সুনির্দিষ্টভাবে - এটি অক্ষম করুন এবং পাঠ্যটির একটি একক লাইন ভেরিয়েবলে পড়ুন। এটি যদি না থাকে readতবে প্রতিটি পৃথক শব্দকে lineভেরিয়েবলের সাথে ফিট করার চেষ্টা করা হবে । তবে এটি আরেকটি গল্প, যা আমি আপনাকে পরে পড়াশোনা করতে উত্সাহিত করি, যেহেতু while IFS= read -r variableখুব ঘন ঘন ব্যবহৃত কাঠামো।

প্রতিধ্বনি বনাম প্রিন্টফ আচরণ

echoআপনি এখানে কি আশা করতে চান। এটি আপনার ভেরিয়েবলগুলি ঠিক যেমন readসাজিয়েছে তে প্রদর্শিত করে। এটি পূর্বের আলোচনায় ইতিমধ্যে প্রদর্শিত হয়েছে।

printfএটি অত্যন্ত বিশেষ, কারণ এটিগুলির সমস্ত ক্লান্ত না হওয়া অবধি ফরম্যাট স্ট্রিংয়ে ফিটিং ভেরিয়েবলগুলি রাখা থাকবে। সুতরাং আপনি যখন printf "%d, %d, %d \n" $a $b $cপ্রিন্টফ করেন তখন 3 দশমিকের সাথে ফর্ম্যাট স্ট্রিং দেখতে পান তবে 3 টির চেয়ে বেশি যুক্তি রয়েছে (কারণ আপনার ভেরিয়েবলগুলি প্রকৃতপক্ষে পৃথক 1,2,3,4,5,6 তে প্রসারিত হয়)। এটি বিভ্রান্তিকর লাগতে পারে তবে সি ভাষায় আসল printf() ফাংশনটি কী করে তা থেকে উন্নত আচরণ হিসাবে এটি একটি কারণে উপস্থিত রয়েছে ।

আপনি এখানে যা আউটপুটকে প্রভাবিত করেন তা হ'ল আপনার ভেরিয়েবলগুলি উদ্ধৃত হয় না, যা শেলটি (না printf) ভেরিয়েবলগুলি 6 টি পৃথক আইটেমে বিভক্ত করতে দেয় allows উদ্ধৃতি দিয়ে এটি তুলনা করুন:

bash-4.3$ read a b c <<< "1 2 3 4"
bash-4.3$ printf "%d %d %d\n" "$a" "$b" "$c"
bash: printf: 3 4: invalid number
1 2 3

$cভেরিয়েবলটি উদ্ধৃত হবার কারণে , এটি এখন একটি সম্পূর্ণ স্ট্রিং হিসাবে স্বীকৃত 3 4, এবং এটি %dবিন্যাসে ফিট করে না , যা কেবল একটি একক পূর্ণসংখ্যা

এখন উদ্ধৃতি না দিয়ে একই করুন:

bash-4.3$ printf "%d %d %d\n" $a $b $c
1 2 3
4 0 0

printf আবার বলেছেন: "ঠিক আছে, আপনার কাছে 6 টি আইটেম রয়েছে তবে ফর্ম্যাটটি কেবল 3 টি দেখায়, তাই আমি ফিটিং স্টাফ রাখি এবং ব্যবহারকারীর আসল ইনপুটটির সাথে আমার যা মেলে না পারে তা ফাঁকা রেখে দেব"।

এবং এই সমস্ত ক্ষেত্রে আপনাকে এর জন্য আমার কথাটি নিতে হবে না। strace -e trace=execveকমান্ডটি আসলে "দেখুন" কী করে তা কেবল নিজের জন্য চালান এবং দেখুন:

bash-4.3$ strace -e trace=execve printf "%d %d %d\n" $a $b $c
execve("/usr/bin/printf", ["printf", "%d %d %d\\n", "1", "2", "3", "4"], [/* 80 vars */]) = 0
1 2 3
4 0 0
+++ exited with 0 +++

bash-4.3$ strace -e trace=execve printf "%d %d %d\n" "$a" "$b" "$c"
execve("/usr/bin/printf", ["printf", "%d %d %d\\n", "1", "2", "3 4"], [/* 80 vars */]) = 0
1 2 printf: 3 4’: value not completely converted
3
+++ exited with 1 +++

অতিরিক্ত নোট

চার্লস ডাফি মন্তব্যে যথাযথভাবে নির্দেশিত হওয়ার সাথে bashসাথে তার নিজস্ব বিল্ট-ইন রয়েছে printfযা আপনি আপনার কমান্ডটিতে ব্যবহার করছেন, straceআসলে /usr/bin/printfশেলটির সংস্করণ নয়, সংস্করণ কল করবে । ছোটখাটো পার্থক্য বাদ দিয়ে, এই বিশেষ প্রশ্নের প্রতি আমাদের আগ্রহের জন্য স্ট্যান্ডার্ড ফর্ম্যাট স্পেসিফায়ার একই এবং আচরণ একই।

যে বিষয়টি মনে রাখা উচিত তা হল printfসিনট্যাক্সটি echoসি বা অন্য কোনও সি-এর মতো ভাষার সাথে পরিচিত যা printf()এটিতে কাজ করে তার চেয়ে অনেক বেশি বহনযোগ্য (এবং তাই পছন্দসই) than বনাম বিষয়ে টেরডনের দ্বারা এই দুর্দান্ত উত্তরটি দেখুন । আপনি যদি উবুন্টুর নির্দিষ্ট সংস্করণে আপনার নির্দিষ্ট শেলের সাথে আউটপুট তৈরি করতে পারেন তবে আপনি যদি বিভিন্ন সিস্টেমে স্ক্রিপ্টগুলি পোর্ট করতে চলেছেন তবে আপনার সম্ভবত প্রতিধ্বনির চেয়ে পছন্দ করা উচিত । সম্ভবত আপনি উবুন্টু এবং সেন্টোস মেশিনের সাথে কাজ করা একটি শিক্ষানবিস সিস্টেম অ্যাডমিনিস্ট্রেটর, বা এমনকি ফ্রিবিএসডি - কে জানেন - তাই এই ক্ষেত্রে আপনাকে পছন্দ করতে হবে।printfechoprintf

বাশ ম্যানুয়াল থেকে উদ্ধৃতি, বিল্টিন কম্যান্ডস বিভাগে বিক্রয় করুন

[-ers] [-a aname] [-d ডেলিম] [-i পাঠ্য] [-n nchars] [-N nchars] [-p প্রম্পট] [-t টাইমআউট] [-উ fd] [নাম ... ]

একটি লাইন স্ট্যান্ডার্ড ইনপুট থেকে, বা ফাইল বর্ণনাকারী fd থেকে -u বিকল্পের আর্গুমেন্ট হিসাবে সরবরাহ করা হয়, এবং প্রথম শব্দটি প্রথম নামের সাথে, দ্বিতীয় শব্দটির দ্বিতীয় নামতে নির্ধারিত হয়, এবং এভাবেই বাকী থাকে শব্দ এবং তাদের হস্তক্ষেপকারী পৃথক টোড়্স শেষ নাম হিসাবে নির্ধারিত। যদি নামের চেয়ে ইনপুট স্ট্রিম থেকে কম শব্দ পড়ে থাকে তবে অবশিষ্ট নামগুলি খালি মান নির্ধারিত হয়। আইএফএস-এর অক্ষরগুলি শেল সম্প্রসারণের জন্য একই নিয়মগুলি (ওয়ার্ড স্প্লিটিংয়ের নীচে বর্ণিত) ব্যবহার করে একই লাইনগুলিকে শব্দগুলিতে বিভক্ত করতে ব্যবহৃত হয়।


2
straceকেস এবং অন্যটির মধ্যে একটি উল্লেখযোগ্য পার্থক্য - strace printfব্যবহার করছে /usr/bin/printf, যেখানে printfসরাসরি ব্যাশে একই নামে শেল বিল্টিন ব্যবহার করা হচ্ছে। এগুলি সর্বদা অভিন্ন হবে না - উদাহরণস্বরূপ, ব্যাশের উদাহরণটির ফর্ম্যাট স্পেসিফায়ার %qএবং নতুন সংস্করণে $()Tসময় বিন্যাসের জন্য রয়েছে।
চার্লস ডাফি

7

এটি কেবলমাত্র একটি পরামর্শ এবং সের্গির উত্তরটি মোটেও প্রতিস্থাপনের উদ্দেশ্যে নয়। আমি মনে করি যে সের্গি তারা মুদ্রণের ক্ষেত্রে আলাদা কেন তা নিয়ে দুর্দান্ত উত্তর লিখেছিল। কিভাবে পড়ুন পরিবর্তনশীল মধ্যে অবশিষ্ট সঙ্গে নির্ধারিত পরার $cহিসাবে পরিবর্তনশীল 3 4 5 6পর 1এবং 2হস্তান্তর করা হয়েছে aএবং bechoআপনার জন্য পরিবর্তনশীল বিভক্ত হবে না যেখানে এস printfসঙ্গে %d

আপনি তবে কমান্ডের শুরুতে সংখ্যার প্রতিধ্বনি চালিত করে মূলত আপনাকে একই উত্তরগুলি দিতে পারেন:

ইন /bin/bashআপনি ব্যবহার করতে পারেন:

echo -e "1 2 3 \n4 5 6"

ইন /bin/shআপনি শুধু ব্যবহার করতে পারেন:

echo "1 2 3 \n4 5 6"

বাশ-\ অব্যাহতি অক্ষরগুলি সক্ষম করার জন্য -e ব্যবহার করে যেখানে sh এর এটির প্রয়োজন নেই কারণ এটি ইতিমধ্যে সক্ষম রয়েছে। \nএটি একটি নতুন লাইন তৈরি করে তোলে, সুতরাং এখন প্রতিধ্বনি লাইনটি দুটি পৃথক লাইনে বিভক্ত হয়ে গেছে যা এখন আপনার প্রতিধ্বনি লুপের বিবৃতিতে দু'বার ব্যবহার করা যেতে পারে:

:~$ echo -e "1 2 3 \n4 5 6" | while read a b c; do echo "$a, $b, $c"; done
1, 2, 3
4, 5, 6

যা printfকমান্ডটি ব্যবহার করে একই আউটপুট তৈরি করে :

:~$ echo -e "1 2 3 \n4 5 6" | while read a b c ;do printf "%d, %d, %d \n" $a $b $c; done
1, 2, 3 
4, 5, 6 

ভিতরে sh

$ echo "1 2 3 \n4 5 6" | while read a b c; do echo "$a, $b, $c"; done
1, 2, 3
4, 5, 6
$ echo "1 2 3 \n4 5 6" | while read a b c ;do printf "%d, %d, %d \n" $a $b $c; done
1, 2, 3 
4, 5, 6 

আশাকরি এটা সাহায্য করবে!


echo -ePOSIX মাত্র একটি এক্সটেনশন নয় - কিন্তু কোন echoযে বের না হয় -eদেওয়া যে ইনপুট আসলে defying হয় / কালো অক্ষর স্পেসিফিকেশন ভঙ্গ তার আউটপুট উপর। (ব্যাশ ডিফল্টরূপে noncompliant, কিন্তু যখন উভয় মান মেনে চলে posixএবং xpg_echoপতাকা নির্ধারণ করা হয় দ্বিতীয়টি পারেন কম্পাইল-সময়ে ডিফল্ট তৈরি করা, যার মানে হল না ব্যাশ সমস্ত সংস্করণের সাথে কাজ করবে echo -eতুমি এখানে আশা হিসাবে)।
চার্লস ডাফি 15

Pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html এর জন্য POSIX বিশেষের অ্যাপ্লিকেশন ইউজেজecho এবং রেশনাল বিভাগগুলি দেখুন , স্পষ্টভাবে বর্ণনা করেছেন যে ইনপুটটিতে কোথাও বা ব্যাকস্ল্যাশগুলির echoউপস্থিতিতে তার আচরণটি অনির্ধারিত -n, এবং পরামর্শ দিচ্ছেন যে printfপরিবর্তে ব্যবহার করা হবে।
চার্লস ডাফি

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

3
উবুন্টুকে জিজ্ঞাসা করুন @ চার্লসডুফি আমরা মাঝে মাঝে এমন উত্তর লিখি যা অন্য লিনাক্স ডিস্ট্রোজে পরিবহনযোগ্য নয়। আপনার প্রতিনিধি এখানে মাত্র 103 পয়েন্ট হিসাবে আপনি এটি খেয়াল নাও করতে পারেন। স্ট্যাক ওভারফ্লোতে আপনার প্রতিনিধি যদিও 123.3 কে পয়েন্ট তাই আপনি স্পষ্টতই * এনআইএক্স সিস্টেমগুলি সম্পর্কে এক টন স্টাফ জানেন। আমি মনে করি আপনি, টেরেস এবং সার্জ ঠিক আছেন তবে বিভিন্ন কোণ থেকে থ্রেডটি দেখছেন। আপনার কাছে এমন কোনও উত্তর লিখার অনুভূতি প্রতিধ্বনিত করছি (কোনও শঙ্কিত উদ্দেশ্য নয়) যা * এনআইএক্স পোর্টেবল, বা লিনাক্স ডিস্ট্রোস জুড়ে কমপক্ষে পোর্টেবল।
WinEunuuchs2Unix

2
@ চার্লসডুফি আমি যখন আপনার সংবেদনের সাথে একমত হই তবে উত্তরগুলি বহনযোগ্য করে তোলা উচিত , তবে এটি উবুন্টু-ভিত্তিক সাইট, সুতরাং উবুন্টু-নির্দিষ্ট সরঞ্জামগুলি ব্যবহারকারীদের ধরে নেওয়া উচিত। সুতরাং সতর্কতা কিছুটা অন্তর্নিহিত হয়। আসুন মাত্রাতিরিক্ত দীর্ঘ আলোচনায় যাওয়া উচিত। আপনি ঠিক বলেছেন যে অন্যান্য শাঁস বিবেচনা করা উচিত, এবং উত্তরগুলি থেকে শিখতে পড়া নবাবিদেরও সেই সাথে বিবেচনা করা উচিত। একটি সংক্ষিপ্ত মন্তব্য সম্ভবত বিষয়টি বলতে যথেষ্ট হবে।
সের্গেই কোলোডিয়াজনি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.