আইএফএস = পড়ার সময় I আইএফএস = এর পরিবর্তে কেন প্রায়ই ব্যবহার করা হয়; পড়ার সময়..`?


81

মনে হয় যে স্বাভাবিক অনুশীলনটি প্রতিটি পুনরাবৃত্তির জন্য পুনরায় সেটিংয়ের পুনরুদ্ধার না করার জন্য আইএফএসের সেটিংটি বাইরে রাখবে ... এটি কি কেবল অভ্যাসগত "বানর দেখ, বানর করো" শৈলী, যেমনটি এই বানরের পক্ষে ছিল আমি মানুষ পড়তে পড়তে পড়ি , বা আমি এখানে কিছু সূক্ষ্ম (বা স্পষ্টতই স্পষ্ট) ফাঁদটি অনুপস্থিত?

উত্তর:


82

ফাঁদটি সেটাই

IFS=; while read..

IFSলুপের বাইরে পুরো শেল পরিবেশের জন্য সেট করে whereas

while IFS= read

এটি কেবলমাত্র readঅনুরোধের জন্য পুনরায় সংজ্ঞা দেয় (বোর্ন শেল ব্যতীত)। আপনি যে লুপ পছন্দ করে তা পরীক্ষা করতে পারেন

while IFS= read xxx; ... done

তারপর যেমন লুপ পরে, echo "blabalbla $IFS ooooooo"মুদ্রণ

blabalbla
 ooooooo

যেখানে পরে

IFS=; read xxx; ... done

IFS থাকার বিষয়টি মতেই পুনরায় সংজ্ঞায়িত: এখন echo "blabalbla $IFS ooooooo"কপি করে প্রিন্ট

blabalbla  ooooooo

তাই আপনি যদি দ্বিতীয় ফর্ম ব্যবহার করেন, আপনি পুনরায় সেট করতে মনে রাখতে হবে: IFS=$' \t\n'


এই প্রশ্নের দ্বিতীয় অংশটি এখানে মার্জ করা হয়েছে , সুতরাং আমি সম্পর্কিত উত্তরটি এখান থেকে সরিয়েছি।


ঠিক আছে, মনে হচ্ছে একটি সম্ভাব্য 'ফাঁদ' বাহ্যিক আইএফএস পুনরায় সেট করতে অবহেলা করা ... তবে আমি অবাক হই যে এর আগেও অন্য কিছু ছিল কিনা ... আমি এখানে খুব সুন্দরভাবে জ্বালিয়ে পরীক্ষা করেছি, এবং আমি লক্ষ করুন যে কমান্ডের তালিকাটি আইএফএস স্থাপন করে কোটনের পরে তা অনুসরণ করা হয় কিনা তা নির্ভর করে কোট লিস্টটি ভিন্নভাবে আচরণ করে। আমি এই আচরণটি বুঝতে পারি না (এখনও), এবং আমি এখন ভাবছি যে এই স্তরে কিছু বিশেষ বিবেচনা জড়িত আছে কিনা ... উদাহরণস্বরূপ। while IFS=X readবিভক্ত হয় না X, তবে while IFS=X; readঘটে ...
পিটার.ও

(আপনি অর্ধ কোলন বোঝাচ্ছেন , তাই না?) দ্বিতীয়টি সেমিকোলনে শেষ হওয়ার whileশর্তটি বোঝায় না , সুতরাং প্রকৃত লুপ নেই ... এক-উপাদান লুপের ভিতরে কেবল প্রথম কমান্ড হয়ে যায় ... না ? তখন কি হবে ..? while readdo
rozcietrzewiacz

1
না, অপেক্ষা করুন - আপনি ঠিক বলেছেন, আপনার whileশর্তে বেশ কয়েকটি কমান্ড থাকতে পারে (আগে do)।
rozcietrzewiacz

ওহ .. অবশ্যই, আপনি সেগুলি রাখতে পারেন ... যেমন আপনি বুঝতে পেরেছিলেন ... তবে সেগুলি আধা-কোলন পছন্দ করবে না বলে মনে হয় ... (এবং শেষ কমান্ডটি না দেওয়ার আগ পর্যন্ত লুপটি অ্যাড-ইনফিনিটামকে লুপ করে রাখবে) -জারো প্রস্থান কোড) ... আমি এখন ভাবছি যে ফাঁদটি সম্পূর্ণ ভিন্ন খাতে রয়েছে কিনা ; বুঝতে কিভাবে যে সময় এর কমান্ড তালিকা কাজ করে, যেমন। কেন IFS=কাজ করে, তবে IFS=Xনা ... (অথবা সম্ভবত আমি এটির জন্য কিছুক্ষণের জন্য
ছাড়িয়েছিলাম

1
z রোজিট্রিজেভিয়াক্জ .. ওফস ... আমি আমার আপডেটটি লক্ষ্য করিনি, যখন আমি আমার আপডেটটি সরিয়েছি (পূর্ববর্তী মন্তব্যে উল্লিখিত হিসাবে) .. এটি আকর্ষণীয় দেখায়, এবং এটি বোধ করতে শুরু করে ... তবে এমনকি একটি রাতের জন্যও- আমার মতো পাখি, খুব দেরি হয়ে গেছে ... (আমি কেবল সকালের পাখি শুনেছি:) ... বলেছিল, আমি কিছুটা সমাবেশ করেছি এবং তোমার উদাহরণগুলি পড়েছি ... আমার মনে হয় আমি পেয়েছি, আসলে আমি আমি নিশ্চিত যে আপনি এটি পেয়েছেন, তবে আমার অবশ্যই ঘুমাতে হবে :) ... এটি প্রায় ইউরেকা! মুহূর্ত ... ধন্যবাদ
পিটার.ও

45

আসুন কয়েকটি উদাহরণ সহকারে তৈরি করা ইনপুট পাঠ্য সহ এক নজরে দেখুন:

text=' hello  world\
foo\bar'

এটি দুটি লাইন, প্রথম স্থানটি দিয়ে শুরু এবং ব্যাকস্ল্যাশ দিয়ে শেষ। প্রথমে আসুন দেখে নেওয়া যাক আশেপাশে কোনও সতর্কতা ছাড়াই কী হয় read(তবে কোনও প্রকারের ঝুঁকি ছাড়াই printf '%s\n' "$text"সাবধানে মুদ্রণ করে ব্যবহার করা $text)। (নীচে, $ ‌শেল প্রম্পট দেওয়া আছে।)

$ printf '%s\n' "$text" |
  while read line; do printf '%s\n' "[$line]"; done
[hello worldfoobar]

readব্যাকস্ল্যাশগুলি খেয়েছে: ব্যাকস্ল্যাশ-নিউলাইনमुळे নিউলাইনটিকে উপেক্ষা করা যায় এবং ব্যাকস্ল্যাশ-যে কোনও কিছুই সেই প্রথম ব্যাকস্ল্যাশটিকে উপেক্ষা করে। ব্যাকস্ল্যাশগুলি বিশেষভাবে চিকিত্সা করা এড়াতে আমরা ব্যবহার করি read -r

$ printf '%s\n' "$text" |
  while read -r line; do printf '%s\n' "[$line]"; done
[hello  world\]
[foo\bar]

এটি আরও ভাল, আমাদের প্রত্যাশা অনুযায়ী দুটি লাইন রয়েছে। দুটি লাইনে প্রায় কাঙ্ক্ষিত সামগ্রী থাকে: এর মধ্যে দ্বিগুণ স্থান helloএবং worldধরে রাখা হয়েছে, কারণ এটি lineভেরিয়েবলের মধ্যে রয়েছে। অন্যদিকে, প্রাথমিক স্থানটি খেয়ে ফেলেছিল। এটি কারণ আপনি readযতগুলি শব্দের পাঠ করেন তত পরিমাণে এটি ভেরিয়েবলগুলি ব্যয় করে, শেষের ভেরিয়েবলটিতে বাকী রেখাটি থাকে - তবে এটি এখনও প্রথম শব্দের সাথে শুরু হয়, অর্থাত প্রাথমিক স্পেসগুলি বাতিল করা হয়।

সুতরাং, প্রতিটি লাইন আক্ষরিকভাবে পড়ার জন্য, আমাদের নিশ্চিত করা দরকার যে কোনও শব্দ বিভাজন চলছে না। আমরা IFSভেরিয়েবলটি একটি খালি মানটিতে সেট করে এটি করি ।

$ printf '%s\n' "$text" |
  while IFS= read -r line; do printf '%s\n' "[$line]"; done
[ hello  world\]
[foo\bar]

আমরা অন্তর্নির্মিত IFS সময়কাল জন্য নির্দিষ্টভাবেread সেট কিভাবে নোট করুন । IFS= read -r lineসেট এনভায়রনমেন্ট ভেরিয়েবল IFSবিশেষভাবে কার্যকর করার জন্য (একটি খালি মান) read। এটি সাধারণ সাধারণ কমান্ড সিনট্যাক্সের একটি উদাহরণ : কমান্ডের নাম এবং এর যুক্তিগুলির পরে একটি (সম্ভবত শূন্য) পরিবর্তনশীল অ্যাসাইনমেন্টগুলির অনুক্রম (এছাড়াও আপনি যে কোনও বিন্দুতে পুনর্নির্দেশে ফেলে দিতে পারেন)। যেহেতু readএকটি অন্তর্নির্মিত তাই পরিবর্তনশীল আসলে কোনও বাহ্যিক প্রক্রিয়ার পরিবেশে শেষ হয় না; তবুও $IFSযতক্ষণ readনির্বাহ করা হয় সেখানে আমরা যা নির্ধারণ করছি তার মান ¹ দ্রষ্টব্য যে readকোনও বিশেষ অন্তর্নির্মিত নয় , সুতরাং এই নিয়োগটি কেবলমাত্র তার সময়কালের জন্য স্থায়ী হয়।

সুতরাং আমরা IFSঅন্যান্য নির্দেশাবলীর উপর নির্ভর করতে পারে তার মান পরিবর্তন না করার জন্য যত্ন নিচ্ছি । এই কোডটি আশেপাশের কোডটি IFSপ্রাথমিকভাবে কী সেট করেছে তা কার্যকর হবে এবং লুপের অভ্যন্তরীণ কোডটি নির্ভর করে যদি এটি কোনও সমস্যা করে না IFS

এই কোড স্নিপেটের সাথে বৈসাদৃশ্য করুন, যা কোলন-বিচ্ছিন্ন পথে ফাইল দেখায়। ফাইলের নামের তালিকা একটি ফাইল থেকে পঠিত হয়, প্রতি লাইনে একটি ফাইলের নাম।

IFS=":"; set -f
while IFS= read -r name; do
  for dir in $PATH; do
    ## At this point, "$IFS" is still ":"
    if [ -e "$dir/$name" ]; then echo "$dir/$name"; fi
  done
done <filenames.txt

যদি লুপটি ছিল while IFS=; read -r name; do …, তবে কোলন-বিচ্ছিন্ন উপাদানগুলিতে for dir in $PATHবিভক্ত হবে না $PATH। কোডটি যদি ছিল তবে IFS=; while read …এটি আরও স্পষ্ট হবে যা লুপের বডিতে IFSসেট করা নেই :

অবশ্যই, IFSকার্যকর করার পরে এর মানটি পুনরুদ্ধার করা সম্ভব হবে read। তবে এর জন্য পূর্ববর্তী মানটি জানা দরকার যা অতিরিক্ত প্রচেষ্টা। IFS= readসহজ উপায় (এবং, স্বাচ্ছন্দ্যে, সবচেয়ে সংক্ষিপ্ততম উপায়))

¹ এবং, যদি readকোনও আটকা পড়া সংকেত দ্বারা বাধাগ্রস্ত হয়, সম্ভবত ট্র্যাপটি কার্যকর করা অবস্থায় - এটি পসিক্স দ্বারা নির্দিষ্ট করা হয়নি এবং বাস্তবে শেলের উপর নির্ভর করে।


4
থ্যাঙ্কস গিলস .. খুব সুন্দর গাইডেড ট্যুর .. (আপনি কি 'সেট-ফ' বলতে চাইছেন?) .... এখন পাঠকের জন্য যা ইতিমধ্যে যা বলা হয়েছে তা পুনরুদ্ধার করতে আমি যে ইস্যুটিতে জোর দিয়েছি তা বলতে চাই আমি এটিকে ভুল উপায়ে দেখছি। প্রথম এবং সর্বাগ্রে সত্য যে কনস্ট্রাক্ট while IFS= read(পরে অর্ধ-কোলন ব্যতীত =) এর বা এর বা এর কোনও বিশেষ রূপ নয় .. কনস্ট্রাক্টটি জেনেরিক: অর্থাৎ। । অভাব সেটিং পর সুযোগ তোলে স্থানীয় করার .. যখন - না / সম্পন্ন লুপ 100% সম্পর্কহীন স্থানীয় সুযোগ । whileIFSreadanyvar=anyvalue anycommand;anyvaranyvar anycommandany_var
পিটার.ও

3

এছাড়া (ইতিমধ্যে ব্যাখ্যা) IFSমধ্যে scoping পার্থক্য while IFS='' read, IFS=''; while readএবং while IFS=''; readবাগধারার (প্রতি-কমান্ড বনাম স্ক্রিপ্ট / শেল ব্যাপী IFSপরিবর্তনশীল scoping), নিতে বাড়িতে পাঠ যে আপনার নেতৃস্থানীয় হারাচে এবং একটি ইনপুট লাইনের trailing স্পেস যদি IFS পরিবর্তনশীল (একটি ক) স্থানতে সেট করা আছে।

যদি ফাইল পাথগুলি প্রক্রিয়া করা হয় তবে এটির মারাত্মক গুরুতর পরিণতি হতে পারে।

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

আরও দেখুন: বাশ, আইএফএস সহ ফাইল থেকে লাইন পঠন করুন

(
shopt -s nullglob
touch '  file with spaces   '
IFS=$' \t\n' read -r file <<<"$(printf '%s' *file*with*spaces*)"
ls -l "$file"
IFS='' read -r file <<<"$(printf '%s' *file*with*spaces*)"
ls -l "$file"
)

+1 দুর্দান্ত বিক্ষোভ, 'স্পেস * সহ' আরএম * ফাইল * দিয়ে পরিষ্কার করা
এএমএস

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.