আইএফএস বোঝা


71

এই সাইটটিতে নিম্নলিখিত কয়েকটি থ্রেড এবং স্ট্যাকওভারফ্লো কীভাবে IFSকাজ করে তা বোঝার জন্য সহায়ক ছিল :

তবে আমার এখনও কিছু ছোট প্রশ্ন আছে। আমি তাদের ঠিক একই পোস্টে জিজ্ঞাসা করার সিদ্ধান্ত নিয়েছি কারণ আমি মনে করি এটি ভবিষ্যতের আরও ভাল পাঠকদের সহায়তা করতে পারে:

চতুর্থাংশ 1। IFSসাধারণত "ক্ষেত্র বিভাজন" প্রসঙ্গে আলোচনা করা হয়। কি ক্ষেত্র বিভাজন হিসাবে একই শব্দ বিভাজন ?

প্রশ্ন 2: পসিক্স স্পেসিফিকেশন বলেছেন :

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

সেট IFS=সেট IFSনাল হিসাবে সেট ? এটি কি এটি empty stringখুব সেট করে বোঝানো হচ্ছে ?

Q3: পসিএক্স স্পেসিফিকেশনে, আমি নিম্নলিখিতটি পড়ি :

যদি আইএফএস সেট না করা থাকে তবে শেলটি আইএফএসের মান হিসাবে আচরণ করবে <space>, <tab> and <newline>

বলুন আমি এর ডিফল্ট মানটি পুনরুদ্ধার করতে চাই IFS। আমি কেমন করে ঐটি করি? (আরও নির্দিষ্টভাবে, আমি কীভাবে উল্লেখ করব <tab>এবং <newline>?)

Q4: অবশেষে, এই কোডটি কীভাবে হবে:

while IFS= read -r line
do    
    echo $line
done < /path_to_text_file

আমরা যদি প্রথম লাইনে পরিবর্তন করি তবে আচরণ করুন

while read -r line # Use the default IFS value

অথবা:

while IFS=' ' read -r line

উত্তর:


28
  1. হ্যাঁ, তারা একই।
  2. হ্যাঁ.
  3. ব্যাশ, এবং অনুরূপ শেলগুলিতে আপনি এর মতো কিছু করতে পারেন IFS=$' \t\n'। অন্যথায়, আপনি ব্যবহার করে আক্ষরিক নিয়ন্ত্রণ কোড সন্নিবেশ করতে পারে [space] CTRL+V [tab] CTRL+V [enter]। তবে আপনি যদি এটি করার পরিকল্পনা করছেন তবে পুরানো IFSমানটি অস্থায়ীভাবে সংরক্ষণ করতে অন্য পরিবর্তনশীল ব্যবহার করা ভাল , এবং তারপরে এটি পুনরুদ্ধার করুন (বা var=foo commandসিনট্যাক্স ব্যবহার করে সাময়িকভাবে এটি একটি আদেশের জন্য ওভাররাইড )।
    • প্রথম কোড স্নিপেট পুরো লাইনটি পড়বে, ভারব্যাটিম করে দেবে $line, কারণ শব্দ বিভাজনের জন্য কোনও ক্ষেত্র বিভাজক নেই। মনে রাখবেন যেহেতু অনেকগুলি শাঁস স্ট্রিংগুলি সংরক্ষণের জন্য ক্রাস্টিংগুলি ব্যবহার করে, এনএইউএল-এর প্রথম উদাহরণটি এখনও অকার্যকরভাবে শেষ হওয়ার কারণ হতে পারে।
    • দ্বিতীয় কোড স্নিপেট ইনপুটটির সঠিক কপি না রেখে দিতে পারে $line। উদাহরণস্বরূপ, যদি একাধিক পরপর ক্ষেত্র বিভাজক থাকে তবে সেগুলি প্রথম উপাদানটির একক উদাহরণে তৈরি করা হবে। এটি প্রায়শই আশেপাশের সাদা স্থানের ক্ষতি হিসাবে স্বীকৃত।
    • তৃতীয় কোড স্নিপেট দ্বিতীয়টির মতো একই কাজ করবে, কেবলমাত্র এটি কোনও স্পেসে বিভক্ত হবে (সাধারণ স্থান, ট্যাব বা নিউলাইন নয়)।

3
কিউ 2 এর উত্তরটি ভুল: একটি খালি IFSএবং একটি আনসেট IFSখুব আলাদা। Q4 এর উত্তর আংশিকভাবে ভুল: অভ্যন্তরীণ বিভাজকগুলি এখানে স্পর্শ করা হয় না, কেবল অগ্রণী এবং অনুসরণীয়।
গিলস

3
@ গিলস: কিউ 2 তে প্রদত্ত তিনটি বর্ণের কোনওটিই কোনও আনসেটকে বোঝায় না IFS, তাদের সমস্তটির অর্থ IFS=
স্টাফেন গিমেনেজ

কিউ 2-তে জিলস, আমি কখনও বলিনি যে তারা একই ছিল। আর ভেতরের বিভাজক স্পর্শ করা হয়, যেমন এখানে দেখানো: IFS=' ' ; foo=( bar baz qux ) ; echo "${#foo[@]}"। (এর, কী? সেখানে একাধিক স্পেস ডিলিমিটার থাকতে হবে, এসও ইঞ্জিন সেগুলি সরিয়ে রাখে)।
ক্রিস ডাউন

2
@ স্টাফেনি গিমেনেজ, ক্রিস: ওহ, ঠিক আছে, কিউ 2 সম্পর্কে দুঃখিত, আমি প্রশ্নটি ভুলভাবে লিখেছি। Q4 এর জন্য, আমরা কথা বলছি read; শেষ পরিবর্তনশীলটি সর্বশেষ বিভাজক ব্যতীত যা কিছু বাকি আছে তা ধরে ফেলে এবং অভ্যন্তরীণ বিভাজককে ভিতরে রেখে দেয়।
গিলস

1
গিলস পড়ার দ্বারা ফাঁকা স্থানগুলি সরিয়ে না দেওয়ার বিষয়ে আংশিকভাবে সঠিক। বিশদ জন্য আমার উত্তর পড়ুন।

22

প্রশ্ন 1: হ্যাঁ। "ফিল্ড বিভাজন" এবং "শব্দ বিভাজন" একই ধারণার জন্য দুটি পদ।

প্রশ্ন 2: হ্যাঁ। যদি IFSসেট না করা (যেমন পরে unset IFS) হয়, এটি IFSসেট করা সমান $' \t\n'(একটি স্থান, একটি ট্যাব এবং একটি নতুন লাইন)। যদি IFSএকটি খালি মান সেট করা থাকে (যা এখানে "নাল" মানে এখানে) (অর্থাত্ পরে IFS=বা IFS=''বা IFS=""), কোনও ক্ষেত্র বিভাজন মোটেও সঞ্চালিত হয় না (এবং $*, যা সাধারণত প্রথম অক্ষর ব্যবহার করে $IFS, একটি স্পেস অক্ষর ব্যবহার করে)।

প্রশ্ন 3: আপনি যদি ডিফল্ট IFSআচরণ করতে চান তবে আপনি ব্যবহার করতে পারেন unset IFS। আপনি যদি IFSএই ডিফল্ট মানটিতে স্পষ্টত সেট করতে চান তবে আপনি আক্ষরিক অক্ষর স্থান, ট্যাব, একক উদ্ধৃতিতে নতুন লাইন রাখতে পারেন। Ksh93, ব্যাশ বা zsh এ আপনি ব্যবহার করতে পারেন IFS=$' \t\n'। বহনযোগ্যভাবে, আপনি যদি আপনার উত্স ফাইলে আক্ষরিক ট্যাব অক্ষরটি এড়াতে চান তবে আপনি এটি ব্যবহার করতে পারেন

IFS=" $(echo t | tr t \\t)
"

Q4: IFSএকটি খালি মান read -r lineসেট lineকরা, এটি সম্পূর্ণরূপে নিউলাইন বাদে পুরো লাইনে সেট করে। এর সাথে IFS=" ", শুরুতে এবং লাইনের শেষে ফাঁকাগুলি ছাঁটা হয়। এর ডিফল্ট মান সহ IFS, ট্যাব এবং স্পেসগুলি ছাঁটাই করা হয়।


2
প্রশ্ন 2 আংশিক ভুল। যদি আইএফএস ফাঁকা থাকে, "$ *" বিভাজক ছাড়া যোগ দেওয়া হবে। (কারণ $@, তালিকাবিহীন প্রসঙ্গে যেমন শেলের মধ্যে কিছু পার্থক্য রয়েছে IFS=; var=$@)। এটি লক্ষ করা উচিত যে যখন আইএফএস ফাঁকা থাকে, কোনও শব্দ বিভাজন সুগন্ধযুক্ত হয় না তবে $ var শূন্য থাকে তখন খালি আর্গুমেন্টের পরিবর্তে কোনও যুক্তিতে প্রসারিত হয় না , এবং গ্লোব্বিং এখনও প্রযোজ্য, তাই আপনাকে এখনও ভেরিয়েবল উদ্ধৃত করতে হবে (এমনকি আপনি যদি গ্লোব্বিং অক্ষম করুন)
স্টাফেন চেজেলাস

13

চতুর্থাংশ 1। মাঠ বিভাজন।

ক্ষেত্র বিভাজন শব্দের বিভাজন হিসাবে একই?

হ্যাঁ, উভয়ই একই ধারণাটির প্রতি নির্দেশ দেয়।

প্রশ্ন 2: আইএফএস কখন নাল হয় ?

IFS=''নাল হিসাবে একই সেট করা , খালি স্ট্রিংয়ের মতোও?

হ্যাঁ, তিনটিই একই অর্থ: কোনও ক্ষেত্র / শব্দ বিভাজন করা হবে না। এছাড়াও, এটি মুদ্রণ ক্ষেত্রগুলিকে প্রভাবিত করে (যেমন হিসাবে echo "$*") সমস্ত ক্ষেত্র কোনও স্থান ছাড়াই একত্রিত হবে।

Q3: (অংশ ক) আনসেট আইএফএস।

পসিএক্স স্পেসিফিকেশনে আমি নিম্নলিখিতটি পড়ি :

যদি আইএফএস সেট না করা থাকে তবে শেলটি এমন আচরণ করবে যেন আইএফএসের মান <স্পেস ><tab> <নিউলাইন>

যা হুবহু:

একটি unset IFSদিয়ে শেলটি এমন আচরণ করবে যেন আইএফএস ডিফল্ট থাকে।

তার মানে 'ডিফল্ট আইএফএস মান, বা আনসেট না করে' ফিল্ড বিভাজন 'হুবহু একই রকম হবে।
এর অর্থ এই নয় যে আইএফএস সমস্ত পরিস্থিতিতে একইভাবে কাজ করবে। আরো নির্দিষ্ট হচ্ছে, নির্বাহ OldIFS=$IFSVar সেট হবে OldIFSথেকে নাল , ডিফল্ট না। এবং আইএফএসকে পিছনে সেট করার চেষ্টা করা হচ্ছে, IFS=OldIFSএটি আইএফএসকে বাতিল করে দেবে, আগের মতো সেট না করে রাখবে। সতর্ক থেকো !!.

Q3: (অংশ খ) আইএফএস পুনরুদ্ধার করুন।

আমি কীভাবে আইএফএসের মান ডিফল্টে পুনরুদ্ধার করতে পারি। বলুন আমি আইএফএসের ডিফল্ট মানটি পুনরুদ্ধার করতে চাই। আমি কেমন করে ঐটি করি? (আরও সুনির্দিষ্টভাবে, আমি কীভাবে <ট্যাব> এবং <নিউলাইন> উল্লেখ করব ?)

Zsh, ksh, এবং bash (AFAIK) এর জন্য আইএফএসকে ডিফল্ট মান হিসাবে সেট করা যেতে পারে:

IFS=$' \t\n'        # works with zsh, ksh, bash.

হয়ে গেল, আপনাকে আর কিছু পড়তে হবে না।

তবে sh এর জন্য আপনার যদি আইএফএস পুনরায় সেট করতে হয় তবে এটি জটিল হয়ে উঠতে পারে।

আসুন কোনও অসুবিধা (জটিলতা ব্যতীত) সম্পূর্ণ করার জন্য সহজ থেকে এক নজরে নেওয়া যাক।

1.- আনসেট আইএফএস।

আমরা কেবল unset IFS(উপরে Q3 অংশ একটি পড়ুন।)।

2.- চরগুলি অদলবদল।

কার্যকারণ হিসাবে, ট্যাব এবং নিউলাইনটির মান অদলবদল করা আইএফএসের মান সেট করা আরও সহজ করে তোলে এবং তারপরে এটি সমান উপায়ে কাজ করে।

আইএফএসকে <স্পেস> << নিউলাইন> <ট্যাব> এ সেট করুন :

sh -c 'IFS=$(echo " \n\t"); printf "%s" "$IFS"|xxd'      # Works.

3.- একটি সরল? সমাধান:

যদি এমন কোনও শিশু স্ক্রিপ্ট থাকে যা আইএফএসের সঠিকভাবে সেট করা থাকে তবে আপনি সর্বদা ম্যানুয়ালি লিখতে পারেন:

IFS = '   
'

যেখানে ম্যানুয়ালি টাইপ করা ক্রমটি ছিল:, IFS='spacetabnewline'ক্রমটি যা আসলে উপরে উপরে সঠিকভাবে টাইপ করা হয়েছে (আপনার যদি নিশ্চিত করার প্রয়োজন হয় তবে এই উত্তরটি সম্পাদনা করুন)। তবে আপনার ব্রাউজারের একটি অনুলিপি / পেস্ট বিচ্ছিন্ন হয়ে যাবে কারণ ব্রাউজারটি সাদা জায়গা স্পর্শ করবে / গোপন করবে। উপরে লিখিতভাবে কোড ভাগ করে নেওয়া কঠিন করে তোলে।

4.- সম্পূর্ণ সমাধান।

সুরক্ষিতভাবে অনুলিপি করা যায় এমন কোডটি লিখতে সাধারণত অসম্পূর্ণ মুদ্রণযোগ্য পলায়ন জড়িত।

আমাদের এমন কিছু কোড দরকার যা প্রত্যাশিত মানটি "উত্পাদন" করে। তবে, ধারণাটি সঠিক হলেও, এই কোডটি কোনও পূর্ববর্তী সেট করবে না \n:

sh -c 'IFS=$(echo " \t\n"); printf "%s" "$IFS"|xxd'      # wrong.

এটি ঘটে কারণ বেশিরভাগ শাঁসের নীচে, বিস্তৃত হওয়ার পরে সমস্ত অনুসরণযোগ্য নিউলাইনগুলি $(...)বা `...`কমান্ডের বিকল্পগুলি সরানো হয়।

Sh এর জন্য আমাদের একটি কৌশল ব্যবহার করা দরকার :

sh -c 'IFS="$(printf " \t\nx")"; IFS="${IFS%x}"; printf "$IFS"|xxd'  # Correct.

বিকল্প উপায়টি হ'ল বাফ (উদাহরণস্বরূপ) থেকে পরিবেশগত মান হিসাবে আইএফএস সেট করা এবং তারপরে sh কল (এটির সংস্করণগুলি যা আইএফএসকে পরিবেশের মাধ্যমে সেট করার জন্য স্বীকৃতি দেয়) এইভাবে কল করুন:

env IFS=$' \t\n' sh -c 'printf "%s" "$IFS"|xxd'

সংক্ষেপে, sh আইএফএসকে পুনরায় সেট করার পক্ষে বেশ একটি বিজোড় অ্যাডভেঞ্চার।

Q4: আসল কোডে:

শেষ পর্যন্ত, এই কোডটি কীভাবে হবে:

while IFS= read -r line
do
    echo $line
done < /path_to_text_file

আমরা যদি প্রথম লাইনে পরিবর্তন করি তবে আচরণ করুন

while read -r line # Use the default IFS value

অথবা:

while IFS=' ' read -r line

প্রথম: আমি জানি না echo $line(বর্ণিত উদ্ধৃতি সহ) পার্পাউসটিতে আছে কি নেই। এটি 'ফিল্ড বিভাজন' এর দ্বিতীয় স্তরের পরিচয় করিয়ে দেয় যা পঠনযোগ্য নয়। সুতরাং আমি উভয় জবাব দেব। :)

এই কোড সহ (যাতে আপনি নিশ্চিত করতে পারেন)। আপনার দরকারী এক্সএক্সডি প্রয়োজন হবে :

#!/bin/ksh
# Correctly set IFS as described above.
defIFS="$(printf " \t\nx")"; defIFS="${defIFS%x}";
IFS="$defIFS"
printf "IFS value: "
printf "%s" "$IFS"| xxd -p

a='   bar   baz   quz   '; l="${#a}"
printf "var value          : %${l}s-" "$a" ; printf "%s\n" "$a" | xxd -p

printf "%s\n" "$a" | while IFS='x' read -r line; do
    printf "IFS --x--          : %${l}s-" "$line" ;
    printf "%s" "$line" |xxd -p; done;

printf 'Values      quoted :\n' ""  # With values quoted:
printf "%s\n" "$a" | while IFS='' read -r line; do
    printf "IFS null    quoted : %${l}s-" "$line" ;
    printf "%s" "$line" |xxd -p; done;

printf "%s\n" "$a" | while IFS="$defIFS" read -r line; do
    printf "IFS default quoted : %${l}s-" "$line" ;
    printf "%s" "$line" |xxd -p; done;

unset IFS; printf "%s\n" "$a" | while read -r line; do
    printf "IFS unset   quoted : %${l}s-" "$line" ;
    printf "%s" "$line" |xxd -p; done;
    IFS="$defIFS"   # set IFS back to default.

printf "%s\n" "$a" | while IFS=' ' read -r line; do
    printf "IFS space   quoted : %${l}s-" "$line" ;
    printf "%s" "$line" |xxd -p; done;

printf '%s\n' "Values unquoted :"   # Now with values unquoted:
printf "%s\n" "$a" | while IFS='x' read -r line; do
    printf "IFS --x-- unquoted : "
    printf "%s, " $line; printf "%s," $line |xxd -p; done

printf "%s\n" "$a" | while IFS='' read -r line; do
    printf "IFS null  unquoted : ";
    printf "%s, " $line; printf "%s," $line |xxd -p; done

printf "%s\n" "$a" | while IFS="$defIFS" read -r line; do
    printf "IFS defau unquoted : ";
    printf "%s, " $line; printf "%s," $line |xxd -p; done

unset IFS; printf "%s\n" "$a" | while read -r line; do
    printf "IFS unset unquoted : ";
    printf "%s, " $line; printf "%s," $line |xxd -p; done
    IFS="$defIFS"   # set IFS back to default.

printf "%s\n" "$a" | while IFS=' ' read -r line; do
    printf "IFS space unquoted : ";
    printf "%s, " $line; printf "%s," $line |xxd -p; done

আমি পাই:

$ ./stackexchange-Understanding-IFS.sh
IFS value: 20090a
var value          :    bar   baz   quz   -20202062617220202062617a20202071757a2020200a
IFS --x--          :    bar   baz   quz   -20202062617220202062617a20202071757a202020
Values      quoted :
IFS null    quoted :    bar   baz   quz   -20202062617220202062617a20202071757a202020
IFS default quoted :       bar   baz   quz-62617220202062617a20202071757a
IFS unset   quoted :       bar   baz   quz-62617220202062617a20202071757a
IFS space   quoted :       bar   baz   quz-62617220202062617a20202071757a
Values unquoted :
IFS --x-- unquoted : bar, baz, quz, 6261722c62617a2c71757a2c
IFS null  unquoted : bar, baz, quz, 6261722c62617a2c71757a2c
IFS defau unquoted : bar, baz, quz, 6261722c62617a2c71757a2c
IFS unset unquoted : bar, baz, quz, 6261722c62617a2c71757a2c
IFS space unquoted : bar, baz, quz, 6261722c62617a2c71757a2c

প্রথম মানটি হ'ল সঠিক মান IFS='spacetabnewline'

পরের লাইনটি হ'ল ভার্সের সমস্ত হেক্স মান $a, এবং প্রতিটি পঠিত কমান্ডকে একটি নতুন লাইন '0 এ' হিসাবে দেওয়া হবে।

পরবর্তী লাইনটি, যার জন্য আইএফএস নাল, কোনও 'ফিল্ড বিভাজন' সম্পাদন করে না, তবে নতুন লাইনটি সরানো হয়েছে (প্রত্যাশার মতো)।

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

শেষ চারটি লাইন দেখায় যে একটি অব্যক্ত ভেরিয়েবল কী করবে। মানগুলি (কয়েকটি) স্পেসে বিভক্ত হবে এবং এটি মুদ্রিত হবে:bar,baz,qux,


4

unset IFS আইএফএস পরিষ্কার করে, এমনকি যদি আইএফএসের পরে "\ t \ n" বলে ধরে নেওয়া হয়:

$ echo "'$IFS'"
'   
'
$ IFS=""
$ echo "'$IFS'"
''
$ unset IFS
$ echo "'$IFS'"
''
$ IFS=$' \t\n'
$ echo "'$IFS'"
'   
'
$

একই আচরণের সাথে বাশ সংস্করণ 4.2.45 এবং 3.2.25 এ পরীক্ষিত।


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