সামঞ্জস্যপূর্ণ উত্তর
এটি করার বিভিন্ন উপায় রয়েছে সজোরে আঘাত।
তবে, এটি প্রথমে লক্ষ্য করা গুরুত্বপূর্ণ যে bash
এর মধ্যে অনেকগুলি বিশেষ বৈশিষ্ট্য রয়েছে (তথাকথিত বাশিজম ) যা অন্য কোনও ক্ষেত্রে কাজ করবে নাখোল।
বিশেষত, অ্যারে , এসোসিয়েটিভ অ্যারে এবং প্যাটার্ন সাবস্টিটিউশন , যা এই পোস্টের সমাধানগুলিতে এবং থ্রেডে থাকা অন্যদের মধ্যে ব্যবহৃত হয়, তা বাশিজম এবং এটি অন্যান্য শেলগুলির অধীনে কাজ না করে যা অনেক লোক ব্যবহার করে।
উদাহরণস্বরূপ: আমার ডেবিয়ান জিএনইউ / লিনাক্সে , একটি মানক শেল বলা হয়হানাহানি; আমি এমন অনেক লোককে জানি যারা নামক একটি শেল ব্যবহার করতে পছন্দ করেksh; এবং একটি বিশেষ সরঞ্জামও বলা হয়, busybox তার নিজের শেল দোভাষী সাথে (ছাই)।
অনুরোধ করা স্ট্রিং
উপরের প্রশ্নের বিভাজনে স্ট্রিংটি হ'ল:
IN="bla@some.com;john@home.com"
আমি এই স্ট্রিংয়ের একটি পরিবর্তিত সংস্করণ ব্যবহার করব তা নিশ্চিত করার জন্য যে আমার সমাধানটি সাদা স্থানযুক্ত স্ট্রিংগুলির শক্ত, যা অন্যান্য সমাধানগুলিকে ভেঙে ফেলতে পারে:
IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
ডিলিমিটার ইন এর উপর ভিত্তি করে বিভক্ত স্ট্রিং সজোরে আঘাত (সংস্করণ> = 4.2)
ইন বিশুদ্ধ bash
, আমরা একটি তৈরি করতে পারেন অ্যারের জন্য একটি অস্থায়ী মান উপাদানের বিভক্ত সঙ্গে IFS ( ইনপুট ক্ষেত্র বিভাজক )। আইএফএস, অন্যান্য বিষয়গুলির মধ্যেও বলে bash
যে অ্যারের সংজ্ঞা দেওয়ার সময় উপাদানগুলির মধ্যে এটি কোন অক্ষর (গুলি) হিসাবে আচরণ করা উচিত:
IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
# save original IFS value so we can restore it later
oIFS="$IFS"
IFS=";"
declare -a fields=($IN)
IFS="$oIFS"
unset oIFS
এর নতুন সংস্করণগুলিতে bash
, আইএফএস সংজ্ঞা সহ একটি কমান্ডের উপসর্গ করা কেবল সেই কমান্ডের জন্য আইএফএস পরিবর্তন করে এবং তত্ক্ষণাত পূর্ববর্তী মানটিতে পুনরায় সেট করে। এর অর্থ আমরা উপরেরটি কেবল একটি লাইনে করতে পারি:
IFS=\; read -a fields <<<"$IN"
# after this command, the IFS resets back to its previous value (here, the default):
set | grep ^IFS=
# IFS=$' \t\n'
আমরা দেখতে পাচ্ছি যে স্ট্রিংটি সেমিকোলনে বিভক্ত IN
নামের একটি অ্যারেতে সংরক্ষণ করা হয়েছে fields
:
set | grep ^fields=\\\|^IN=
# fields=([0]="bla@some.com" [1]="john@home.com" [2]="Full Name <fulnam@other.org>")
# IN='bla@some.com;john@home.com;Full Name <fulnam@other.org>'
(আমরা এই ভেরিয়েবলের সামগ্রীগুলি ব্যবহার করেও প্রদর্শন করতে পারি declare -p
:)
declare -p IN fields
# declare -- IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
# declare -a fields=([0]="bla@some.com" [1]="john@home.com" [2]="Full Name <fulnam@other.org>")
নোটটি read
হ'ল বিভাজনটি করার দ্রুততম উপায় কারণ সেখানে কাঁটাচামচ বা বাহ্যিক সংস্থান বলা হয়নি।
অ্যারে সংজ্ঞায়িত হয়ে গেলে, আপনি প্রতিটি ক্ষেত্রটি প্রক্রিয়া করার জন্য একটি সাধারণ লুপ ব্যবহার করতে পারেন (বা বরং, অ্যারের প্রতিটি উপাদান আপনি এখন সংজ্ঞা দিয়ে দিয়েছেন):
# `"${fields[@]}"` expands to return every element of `fields` array as a separate argument
for x in "${fields[@]}" ;do
echo "> [$x]"
done
# > [bla@some.com]
# > [john@home.com]
# > [Full Name <fulnam@other.org>]
অথবা আপনি স্থানান্তরিত পদ্ধতির সাহায্যে প্রসেসিংয়ের পরে অ্যারে থেকে প্রতিটি ক্ষেত্রটি ফেলে দিতে পারেন, যা আমার পছন্দ:
while [ "$fields" ] ;do
echo "> [$fields]"
# slice the array
fields=("${fields[@]:1}")
done
# > [bla@some.com]
# > [john@home.com]
# > [Full Name <fulnam@other.org>]
এবং যদি আপনি কেবল অ্যারের একটি সাধারণ মুদ্রণযন্ত্র চান তবে আপনার এটির লুপ করার দরকারও নেই:
printf "> [%s]\n" "${fields[@]}"
# > [bla@some.com]
# > [john@home.com]
# > [Full Name <fulnam@other.org>]
আপডেট: সাম্প্রতিক সজোরে আঘাত > = 4.4
এর নতুন সংস্করণগুলিতে bash
আপনি কমান্ডটি দিয়ে খেলতে পারেন mapfile
:
mapfile -td \; fields < <(printf "%s\0" "$IN")
এই সিনট্যাক্সটি বিশেষ অক্ষর, নিউলাইন এবং খালি ক্ষেত্র সংরক্ষণ করে!
আপনি যদি খালি ক্ষেত্রগুলি অন্তর্ভুক্ত করতে না চান তবে আপনি নিম্নলিখিতগুলি করতে পারেন:
mapfile -td \; fields <<<"$IN"
fields=("${fields[@]%$'\n'}") # drop '\n' added by '<<<'
এর সাথে mapfile
, আপনি অ্যারে ঘোষণা করতে এবং এলোমেলোভাবে সীমিত উপাদানগুলির উপর "লুপ" এড়াতে পারেন, প্রতিটিটিতে একটি ফাংশন ডেকে:
myPubliMail() {
printf "Seq: %6d: Sending mail to '%s'..." $1 "$2"
# mail -s "This is not a spam..." "$2" </path/to/body
printf "\e[3D, done.\n"
}
mapfile < <(printf "%s\0" "$IN") -td \; -c 1 -C myPubliMail
(দ্রষ্টব্য: \0
আপনি যদি স্ট্রিংয়ের শেষে খালি ক্ষেত্রগুলির বিষয়ে চিন্তা না করেন বা তারা উপস্থিত না হন তবে বিন্যাসের স্ট্রিংয়ের শেষে অকেজো হয়))
mapfile < <(echo -n "$IN") -td \; -c 1 -C myPubliMail
# Seq: 0: Sending mail to 'bla@some.com', done.
# Seq: 1: Sending mail to 'john@home.com', done.
# Seq: 2: Sending mail to 'Full Name <fulnam@other.org>', done.
অথবা আপনি ব্যবহার করতে পারেন <<<
, এবং ফাংশন বডিতে এতে যুক্ত হওয়া নতুন লাইনটি ফেলে দেওয়ার জন্য কিছু প্রক্রিয়াকরণ অন্তর্ভুক্ত রয়েছে:
myPubliMail() {
local seq=$1 dest="${2%$'\n'}"
printf "Seq: %6d: Sending mail to '%s'..." $seq "$dest"
# mail -s "This is not a spam..." "$dest" </path/to/body
printf "\e[3D, done.\n"
}
mapfile <<<"$IN" -td \; -c 1 -C myPubliMail
# Renders the same output:
# Seq: 0: Sending mail to 'bla@some.com', done.
# Seq: 1: Sending mail to 'john@home.com', done.
# Seq: 2: Sending mail to 'Full Name <fulnam@other.org>', done.
ডিলিমিটার ইন এর উপর ভিত্তি করে বিভক্ত স্ট্রিং খোল
আপনি যদি ব্যবহার করতে না পারেন bash
, বা আপনি যদি এমন কিছু লিখতে চান যা বিভিন্ন শেল ব্যবহার করা যায় তবে আপনি প্রায়শই বাশিজম ব্যবহার করতে পারবেন না - এবং এর মধ্যে আমরা উপরের সমাধানগুলিতে যে অ্যারেগুলি ব্যবহার করেছি তা অন্তর্ভুক্ত রয়েছে।
তবে, স্ট্রিংয়ের "উপাদানগুলি" লুপ করতে আমাদের অ্যারে ব্যবহার করার দরকার নেই। কোনও প্যাটার্নের প্রথম বা শেষ ঘটনা থেকে কোনও স্ট্রিংয়ের সাবস্ট্রিংগুলি মোছার জন্য অনেকগুলি শেলের মধ্যে একটি বাক্য গঠন রয়েছে । দ্রষ্টব্য যে *
একটি ওয়াইল্ডকার্ড যা শূন্য বা আরও বেশি অক্ষরের জন্য দাঁড়িয়েছে:
(এখনও অবধি পোস্ট হওয়া কোনও সমাধানে এই পদ্ধতির অভাবই আমি এই উত্তরটি লিখছি তার মূল কারণ;)
${var#*SubStr} # drops substring from start of string up to first occurrence of `SubStr`
${var##*SubStr} # drops substring from start of string up to last occurrence of `SubStr`
${var%SubStr*} # drops substring from last occurrence of `SubStr` to end of string
${var%%SubStr*} # drops substring from first occurrence of `SubStr` to end of string
স্কোর_উন্ডারের দ্বারা ব্যাখ্যা করা হয়েছে :
#
এবং যথাক্রমে স্ট্রিংয়ের শুরু এবং শেষ%
থেকে সংক্ষিপ্ততম ম্যাচিং স্ট্রিংিং মুছুন এবং
##
এবং %%
দীর্ঘতম সম্ভাব্য মিলের সাবস্ট্রিং মুছুন।
উপরের সিনট্যাক্সটি ব্যবহার করে, আমরা একটি পদ্ধতির তৈরি করতে পারি যেখানে ডিলিমিটারের উপরে বা তার পরে সাবস্ট্রিংগুলি মুছে ফেলে আমরা স্ট্রিং থেকে "উপাদানগুলি" সাবস্ট্রিং বের করি।
নীচে কোডব্লক ভাল কাজ করে সজোরে আঘাত(ম্যাক ওএস সহ bash
),হানাহানি, ksh, এবং , busyboxএর ছাই:
IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
while [ "$IN" ] ;do
# extract the substring from start of string up to delimiter.
# this is the first "element" of the string.
iter=${IN%%;*}
echo "> [$iter]"
# if there's only one element left, set `IN` to an empty string.
# this causes us to exit this `while` loop.
# else, we delete the first "element" of the string from IN, and move onto the next.
[ "$IN" = "$iter" ] && \
IN='' || \
IN="${IN#*;}"
done
# > [bla@some.com]
# > [john@home.com]
# > [Full Name <fulnam@other.org>]
আনন্দ কর!