ডিলিমিটার দ্বারা স্ট্রিং বিভক্ত করুন এবং এন-তম উপাদান পান


75

আমার একটি স্ট্রিং রয়েছে:

one_two_three_four_five

আমি একটি পরিবর্তনশীল মধ্যে সংরক্ষণ করতে হবে Aমান twoএবং পরিবর্তনশীল মধ্যে Bমান fourউপরে স্ট্রিং থেকে

উত্তর:


105

ব্যবহার করুন cutসঙ্গে _ক্ষেত্র বিভেদক হিসেবে এবং আকাঙ্ক্ষিত ক্ষেত্র পাবেন:

A="$(cut -d'_' -f2 <<<'one_two_three_four_five')"
B="$(cut -d'_' -f4 <<<'one_two_three_four_five')"

আপনি echoএখানে স্ট্রিংয়ের পরিবর্তে পাইপ ব্যবহার করতে পারেন :

A="$(echo 'one_two_three_four_five' | cut -d'_' -f2)"
B="$(echo 'one_two_three_four_five' | cut -d'_' -f4)"

উদাহরণ:

$ s='one_two_three_four_five'

$ A="$(cut -d'_' -f2 <<<"$s")"
$ echo "$A"
two

$ B="$(cut -d'_' -f4 <<<"$s")"
$ echo "$B"
four

কোন বিকল্প আছে? আমি ksh ব্যবহার করছি (bsh নয়) এবং এটি ksh: সিনট্যাক্স ত্রুটি প্রদান করে: `<'অপ্রত্যাশিত
অ্যালেক্স

@ অ্যালেক্স আমার সম্পাদনাগুলি পরীক্ষা করুন।
হিমাইল

উত্তম উত্তর, আমার একটি সামান্য প্রশ্ন আছে: আপনার ভেরিয়েবল "" s "যদি একটি ফোল্ডার হয় তবে কি হবে। আমি যখন কোনও পাথ ফোল্ডারটি কাটানোর চেষ্টা করি তখন আমি নিম্নলিখিতগুলি পছন্দ করি: ILE ILE ফাইল = আমার_উজার / আমার_ফোল্ডার / [ফাইল] * here $ echo $FILE my_user/my_folder/file.csv $ A="$(cut -d'/' -f2 <<<"$FILE")" $ echo $A [file]* আপনি কি জানেন এখানে কী হচ্ছে?
হেনরি নাভরো

1
আর তুমি শুধু গত ক্ষেত্র চাই, শুধুমাত্র শেল builtins ব্যবহার করা হয় তবে - ছাড়াই যখন আপনি ক্ষেত্র সংখ্যা জানি না তার অবস্থান নির্দিষ্ট করতে, অথবা:echo "${s##*_}"
অমিত নাইডু

19

কেবল POSIX sh কনস্ট্রাক্টস ব্যবহার করে, আপনি একবারে একটি ডিলিমিটার পার্স করতে প্যারামিটার সাবস্টিটিউশন কনস্ট্রাক্টস ব্যবহার করতে পারেন । নোট করুন যে এই কোডটি ধরে নিয়েছে যে প্রয়োজনীয় ক্ষেত্রগুলির সংখ্যা রয়েছে, অন্যথায় শেষ ক্ষেত্রটি পুনরাবৃত্তি হয়।

string='one_two_three_four_five'
remainder="$string"
first="${remainder%%_*}"; remainder="${remainder#*_}"
second="${remainder%%_*}"; remainder="${remainder#*_}"
third="${remainder%%_*}"; remainder="${remainder#*_}"
fourth="${remainder%%_*}"; remainder="${remainder#*_}"

বিকল্পভাবে, আপনি ওয়াইল্ডকার্ড সম্প্রসারণ অক্ষম করে এবং IFSডিলিমিটার চরিত্রের সাথে সেট করে একটি অব্যক্ত প্যারামিটার বিকল্প ব্যবহার করতে পারেন (ডিলিমিটারটি যদি একক অ-হোয়াইটস্পেস অক্ষর হয় বা কোনও হোয়াইটস্পেস সিকোয়েন্সটি একটি ডিলিমিটার হয় তবে এটি কেবল কাজ করে)।

string='one_two_three_four_five'
set -f; IFS='_'
set -- $string
second=$2; fourth=$4
set +f; unset IFS

এই ক্লোবারগুলি অবস্থানগত পরামিতি। আপনি যদি কোনও ফাংশনে এটি করেন তবে কেবলমাত্র ফাংশনের অবস্থানগত পরামিতিগুলি প্রভাবিত হবে।

তবুও আরেকটি পদ্ধতি হ'ল readবিল্টিন ব্যবহার করা use

IFS=_ read -r first second third fourth trail <<'EOF'
one_two_three_four_five
EOF

ব্যবহার ডিফল্ট unset IFSফিরে না IFS। এর পরে যদি কারও কারও OldIFS="$IFS"ওল্ডআইএফএসের নালিকাগুলি থাকে। এছাড়াও, এটি ধরে নেওয়া হচ্ছে যে আইএফএসের পূর্বের মানটি ডিফল্ট, যা না হওয়া খুব সম্ভব (এবং দরকারী)। কেবলমাত্র সঠিক সমাধান হ'ল old="$IFS"আইএফএস = "$ পুরানো" দিয়ে সঞ্চয় করা এবং পরে পুনরুদ্ধার করা। বা ... একটি সাব-শেল ব্যবহার করুন (...)। বা, আরও ভাল, আমার উত্তর পড়ুন।
sorontar

@ সোরন্টার ডিফল্ট মানটিতে unset IFSপুনরুদ্ধার করে না IFS, তবে এটি ক্ষেত্র বিভাজনকে ডিফল্ট প্রভাবকে ফিরিয়ে দেয়। হ্যাঁ, এটি একটি সীমাবদ্ধতা, তবে সাধারণত অনুশীলনে এটি একটি গ্রহণযোগ্য। সাব-শেলের সমস্যাটি হ'ল আমাদের এটি থেকে ডেটা বের করা দরকার। আমি এমন একটি সমাধান দেখাব যা শেষ পর্যন্ত রাষ্ট্র পরিবর্তন করে না read। (এটি পসিএক্স শেলগুলিতে কাজ করে, তবে বোর্ন শেলটিতে আইআইআরসি নয় কারণ এটি readএখানে-নথির কারণে সাবসেলে চালানো হবে )) <<<আপনার উত্তর হিসাবে ব্যবহার করা একটি বৈকল্পিক যা কেবল ksh / bash / zsh এ কাজ করে।
গিলস

এমনকি সাব-শেল সম্পর্কে অ্যাট বা হেরলুম শেল নিয়েও আমি কোনও সমস্যা দেখছি না। পরীক্ষিত সমস্ত শেল (পুরানো বোর্ন সহ) প্রধান শেলটিতে সঠিক মান সরবরাহ করে।
sorontar

আমার পথটি যদি এমন কিছু হয় তবে কী হবে user/my_folder/[this_is_my_file]*? আমি কি প্রাপ্ত যখন আমি এই পদক্ষেপগুলি অনুসরণ করুন হল[this_is_my_file]*
হেনরি নাভারো

@ হেনরিনাভারো এই আউটপুটটি আমার উত্তরে কোড স্নিপেটের কোনওটির সাথে মিলে না। তাদের কেউই বিশেষ কিছু করে না /
গিলস

17

একটি awkউত্তর দেখতে চেয়েছিলেন , সুতরাং এখানে একটি:

A=$(awk -F_ '{print $2}' <<< 'one_two_three_four_five')
B=$(awk -F_ '{print $4}' <<< 'one_two_three_four_five')

1
এবং যদি আপনি শেষ টুকরোটি চান - তবে এর অবস্থান নির্দিষ্ট করার প্রয়োজন ছাড়াই বা যখন আপনি ক্ষেত্রের সংখ্যা জানেন না:awk -F_ '{print $NF}' <<< 'one_two_3_4_five'
অমিত নাইডু

8

সবচেয়ে সহজ উপায় (<<< সহ শাঁসের জন্য) হ'ল:

 IFS='_' read -r a second a fourth a <<<"$string"

$aপরিবর্তে একটি টেম্পোরাল ভেরিয়েবল ব্যবহার করা হচ্ছে $_কারণ একটি শেল অভিযোগ করে।

একটি পূর্ণ স্ক্রিপ্টে:

 string='one_two_three_four_five'
 IFS='_' read -r a second a fourth a <<<"$string"
 echo "$second $fourth"

কোনও আইএফএস পরিবর্তন হচ্ছে না, set -f(পথের নাম সম্প্রসারণ) নিয়ে ইস্যু নয়, অবস্থানগত পরামিতিগুলিতে কোনও পরিবর্তন নেই ("$ @")।


আইএফএস পরিবর্তন না করে সমস্ত শেলের (হ্যাঁ, সমস্ত পসিক্স অন্তর্ভুক্ত) পোর্টেবল সমাধানের জন্য বা set -f(কিছুটা জটিল) হেরিডোক সমতুল্য ব্যবহার করুন:

string='one_two_three_four_five'

IFS='_' read -r a second a fourth a <<-_EOF_
$string
_EOF_

echo "$second $fourth"

বুঝতে হবে যে এই সমাধানগুলি (এখানে-ডক এবং এর ব্যবহার উভয়ই <<<সব পেছনের নতুন লাইনগুলি সরিয়ে ফেলবে
And এবং এটি একটি "এক লাইনার" ভেরিয়েবল কনটেন্টের জন্য ডিজাইন করা হয়েছে
multi মাল্টি-লাইনারগুলির জন্য সমাধানগুলি সম্ভব তবে আরও জটিল কাঠামোগত প্রয়োজন।


ব্যাশ সংস্করণ ৪.৪-তে একটি খুব সহজ সমাধান সম্ভব

readarray -d _ -t arr <<<"$string"

echo "array ${arr[1]} ${arr[3]}"   # array numbers are zero based.

অনেকগুলি পসিক্স শেলের জন্য অ্যারে না থাকায় পসিএক্স শেলগুলির সমতুল্য নেই।

অ্যারে রয়েছে এমন শেলগুলির জন্য এটি
এতটা সহজ হতে পারে: (আতশ, লক্ষ, মক্ষ, কেএসএইচ, এবং বাশে কাজ করার জন্য পরীক্ষিত)

set -f; IFS=_; arr=($string)

তবে ভেরিয়েবল এবং বিকল্পগুলি রাখতে এবং পুনরায় সেট করতে প্রচুর অতিরিক্ত নদীর গভীরতানির্ণয় সহ:

string='one_* *_three_four_five'

case $- in
    *f*) noglobset=true; ;;
    *) noglobset=false;;
esac

oldIFS="$IFS"

set -f; IFS=_; arr=($string)

if $noglobset; then set -f; else set +f; fi

echo "two=${arr[1]} four=${arr[3]}"

Zsh এ, অ্যারেগুলি 1 এ শুরু হয় এবং ডিফল্টভাবে স্ট্রিং বিভক্ত হয় না।
সুতরাং zsh এ কাজ করার জন্য কিছু পরিবর্তন করা দরকার।


সমাধানগুলি read যতক্ষণ ব্যবহার করা যায় ততক্ষণ সহজ হয় যতক্ষণ না ওপি একটি দীর্ঘ স্ট্রিং থেকে 76 তম এবং 127 তম উপাদানগুলি বের করতে চায় না ...
don_crissti

@ ডন_ক্রিসটি ভাল, হ্যাঁ, অবশ্যই, তবে একটি অনুরূপ নির্মাণ: readarrayএই পরিস্থিতির জন্য ব্যবহার করা সহজতর হতে পারে।
sorontar

@ ডন_ক্রিসটি আমি শেলগুলির জন্য অ্যারে সমাধান যুক্ত করেছি that পসিক্স শেলগুলির জন্য, ভাল, অ্যারে না থাকা, 127 উপাদান পর্যন্ত অবস্থানগত পরামিতি কোনও পরিমাপের দ্বারা "সহজ" সমাধান নয়।
sorontar

2

zshআপনি স্ট্রিং (অন _) একটি অ্যারে মধ্যে বিভক্ত করতে পারে সঙ্গে :

elements=(${(s:_:)string})

এবং তারপরে অ্যারে ইনডেক্সের মাধ্যমে প্রতিটি / যে কোনও উপাদান অ্যাক্সেস করুন:

print -r ${elements[4]}

মনে রাখবেন যে মধ্যে zsh(অসদৃশ ksh/ bash) অ্যারে সূচকের 1 এ শুরু


set -fপ্রথম সমাধানটিতে সতর্কতা যুক্ত মনে রাখবেন । ... তারকাচিহ্ন *সম্ভবত?
sorontar

@ সোরন্টার - আপনি কেন আমার প্রয়োজন বলে মনে করেন set -f? আমি read/ ব্যবহার করছি না IFS। আমার সমাধানগুলি যেমন *_*_*বা যাই হোক না কেন স্ট্রিং দিয়ে চেষ্টা করুন ...
don_crissti

Zsh- র জন্য নয়, ব্যবহারকারী একটি ksh সমাধানের জন্য জিজ্ঞাসা করেছিলেন, সুতরাং, তিনি এটি শেলের মধ্যে এটি ব্যবহার করার চেষ্টা করতে পারেন। একটি সতর্কতা তাকে সমস্যা এড়াতে সহায়তা করবে।
sorontar

1

একটি অজগর সমাধান অনুমোদিত?

# python -c "import sys; print sys.argv[1].split('_')[1]" one_two_three_four_five
two

# python -c "import sys; print sys.argv[1].split('_')[3]" one_two_three_four_five
four

না, খারাপ খারাপ উত্তর
রাজ কুমার

0

আর একটি উদার উদাহরণ; বুঝতে সহজ।

A=\`echo one_two_three_four_five | awk -F_ '{print $1}'\`  
B=\`echo one_two_three_four_five | awk -F_ '{print $2}'\`  
C=\`echo one_two_three_four_five | awk -F_ '{print $3}'\`  
... and so on...  

ভেরিয়েবলের সাথেও ব্যবহার করা যেতে পারে।
মনে করুন:
এটি_যাত্রা = "এক_দুই_ তিনটি_চয়দা_ফাইভ"
তারপরে নিম্নলিখিতগুলি কাজ করে:
এ = cho প্রতিধ্বনি $ {this_str} | awk -F_ '{মুদ্রণ $ 1}' `
বি =` প্রতিধ্বনি $ {this_str} | awk -F_ '{মুদ্রণ $ 2}' `
সি =` প্রতিধ্বনি $ {this_str} | awk -F_ '{মুদ্রণ $ 3}' `
... এবং আরও ...

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