আমি কীভাবে বাশের একটি ডিলিমিটারে একটি স্ট্রিং বিভক্ত করব?


2038

আমার কাছে এই স্ট্রিংটি একটি ভেরিয়েবলে সঞ্চিত রয়েছে:

IN="bla@some.com;john@home.com"

এখন আমি ;ডিলিমিটার দিয়ে স্ট্রিংগুলি বিভক্ত করতে চাই যাতে আমার রয়েছে:

ADDR1="bla@some.com"
ADDR2="john@home.com"

অগত্যা আমার ADDR1এবং ADDR2ভেরিয়েবলগুলির প্রয়োজন নেই । যদি তারা কোনও অ্যারের উপাদান হয় তবে এটি আরও ভাল।


নীচের উত্তরগুলি থেকে পরামর্শের পরে, আমি নিম্নলিখিতটি দিয়ে শেষ করেছিলাম যা আমার পরে ছিল:

#!/usr/bin/env bash

IN="bla@some.com;john@home.com"

mails=$(echo $IN | tr ";" "\n")

for addr in $mails
do
    echo "> [$addr]"
done

আউটপুট:

> [bla@some.com]
> [john@home.com]

ইন্টারনাল_ফিল্ড_স্যাপারেটর (আইএফএস) এ সেট করার সাথে একটি সমাধান ছিল ;। আমি নিশ্চিত নই যে উত্তরটি দিয়ে কী হয়েছিল, আপনি কীভাবে IFSডিফল্টে পুনরায় সেট করবেন ?

আরই: IFSসমাধান, আমি এটি চেষ্টা করেছি এবং এটি কাজ করে, আমি পুরানো রাখি IFSএবং তারপরে পুনরুদ্ধার করি:

IN="bla@some.com;john@home.com"

OIFS=$IFS
IFS=';'
mails2=$IN
for x in $mails2
do
    echo "> [$x]"
done

IFS=$OIFS

বিটিডব্লিউ, যখন আমি চেষ্টা করেছি

mails2=($IN)

লুপে প্রিন্ট করার সময় আমি কেবল প্রথম স্ট্রিংটি পেয়েছি, চারপাশে বন্ধনী ব্যবহার $INনা করে।


14
আপনার "সম্পাদনা 2" এর সাথে: আপনি কেবল "আইএফএস আনসেট" করতে পারেন এবং এটি ডিফল্ট অবস্থায় ফিরে আসবে। এটি ইতিমধ্যে কোনও ডিফল্ট মানতে সেট করা হয়েছে এমনটি আশা করার কোনও কারণ না থাকলে এটিকে স্পষ্টভাবে সংরক্ষণ এবং পুনরুদ্ধার করার দরকার নেই। তদুপরি, আপনি যদি কোনও ফাংশনের অভ্যন্তরে এটি করছেন (এবং, আপনি না হন তবে কেন নয়?), আপনি আইএফএসকে স্থানীয় ভেরিয়েবল হিসাবে সেট করতে পারেন এবং ফাংশনটি থেকে বেরিয়ে আসার পরে এটি পূর্ববর্তী মানটিতে ফিরে আসবে।
ব্রুকস মূসা

19
@ ব্রুকস মোজেস: (ক) local IFS=...যেখানে সম্ভব সেখানে ব্যবহারের জন্য +1 ; (খ) -১ এর জন্য unset IFS, এটি আইএফএসকে ঠিক তার ডিফল্ট মানটিতে পুনরায় সেট করে না, যদিও আমি বিশ্বাস করি যে একটি আনসেট আইএফএস আইএফএসের ডিফল্ট মান ($ '\ t \ n') এর মতোই আচরণ করে, তবে এটি খারাপ অভ্যাস বলে মনে হয় অন্ধভাবে অনুমান করুন যে আপনার কোডটি কখনই আইএফএসের সাথে কাস্টম মান হিসাবে সেট করা হবে না; (গ) আরেকটি ধারণা একটি সাব-শেল আহ্বান করা হয়: (IFS=$custom; ...)যখন সাব-শেল আইএফএস থেকে বের হয় তখন এটি যা ছিল তা ফিরে আসবে।
dubiousjim

এক্সিকিউটেবলকে কোথায় ফেলে দিতে হবে তা স্থির করার জন্য আমি কেবল রাস্তাগুলির তদারকি করতে চাই, তাই আমি দৌড়ের পথটি রইলাম ruby -e "puts ENV.fetch('PATH').split(':')"। আপনি যদি খাঁটি বাশ থাকতে চান তবে কোনওরকম স্ক্রিপ্টিং ল্যাঙ্গুয়েজ যে বিল্ট-ইন স্প্লিট রয়েছে তা ব্যবহার করা সহজ।
নিকোগা

4
for x in $(IFS=';';echo $IN); do echo "> [$x]"; done
ব্যবহারকারী 2037659

2
এটি অ্যারে হিসাবে সংরক্ষণ করার জন্য আমাকে অন্য একটি প্রথম বন্ধনী স্থাপন করতে হয়েছিল \nএবং কেবল একটি স্থানের জন্য পরিবর্তন করতে হয়েছিল । সুতরাং চূড়ান্ত লাইন হয় mails=($(echo $IN | tr ";" " "))। সুতরাং এখন আমি mailsঅ্যারের স্বরলিপি ব্যবহার করে mails[index]বা কেবল একটি লুপে পুনরাবৃত্তি করে এর উপাদানগুলি পরীক্ষা করতে পারি
আফ্রিকানস

উত্তর:


1231

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

IFS=';' read -ra ADDR <<< "$IN"
for i in "${ADDR[@]}"; do
    # process "$i"
done

এটি আলাদা করে আইটেমগুলির এক লাইনের বিভাজক করে ;এটিটিকে অ্যারেতে ঠেলে দেবে। পুরো প্রক্রিয়াজাতকরণের জন্য স্টাফ $IN, প্রতিটি সময় এক লাইনের ইনপুট দ্বারা পৃথক করে ;:

 while IFS=';' read -ra ADDR; do
      for i in "${ADDR[@]}"; do
          # process "$i"
      done
 done <<< "$IN"

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

7
ঠিকঠাক প্রয়োগের পরে, কেবল পঠিত কমান্ডের সময়কালের মধ্যে :)
জোহানেস স্কাউব - লিটব

14
আপনি কিছুক্ষণ লুপ ব্যবহার না করে একবারে সবকিছু পড়তে পারেন: পড়ুন -r -d '' -এ একটি অ্যাড্রেসার <<< "The" # -d '' এ এখানে কী, এটি প্রথম নিউলাইনে থামতে না পড়তে বলে ( যা ডিফল্ট -d) তবে ইওএফ বা একটি ন্যুয়াল বাইট অবধি অব্যাহত রাখতে (যা কেবল বাইনারি ডেটাতে ঘটে)।
lhunath

55
@ লুকাবোরিওনিও IFSএকই লাইনে সেট করা readকোনও সেমিকোলন বা অন্য বিভাজক হিসাবে পৃথক কমান্ডের বিপরীতে, এই কমান্ডের মধ্যে রয়েছে - তাই এটি সর্বদা "পুনরুদ্ধার" হয়; আপনাকে ম্যানুয়ালি কিছু করার দরকার নেই।
চার্লস ডাফি

5
@ আইমাজিনেয়ার এটিস্ট্রিং এবং আইএফএসে স্থানীয় পরিবর্তনগুলির সাথে জড়িত একটি বাগ রয়েছে যা $INউদ্ধৃত করা দরকার । বাগটি bash4.3 এ স্থির করা হয়েছে ।
চ্যানার

971

বাশ শেল স্ক্রিপ্ট বিভক্ত অ্যারে থেকে নেওয়া :

IN="bla@some.com;john@home.com"
arrIN=(${IN//;/ })

ব্যাখ্যা:

এই নির্মাণ সব ঘটনার প্রতিস্থাপন ';'(প্রাথমিক //স্ট্রিং মানে বিশ্বব্যাপী প্রতিস্থাপন) INসঙ্গে ' ', (একটি একক স্থান) তারপর একটি অ্যারের হিসাবে শূণ্যস্থান স্ট্রিং ব্যাখ্যা করে (যে কী পার্শ্ববর্তী প্রথম বন্ধনী না)।

প্রতিটি ';'অক্ষরকে একটি ' 'অক্ষর দিয়ে প্রতিস্থাপন করতে কোঁকড়া ধনুর্বন্ধনীগুলির অভ্যন্তরের অভ্যন্তরীণ বাক্য গঠনকে প্যারামিটার এক্সপেনশন বলা হয় ।

কিছু সাধারণ গ্যাটাচ রয়েছে:

  1. যদি মূল স্ট্রিংয়ের স্পেস থাকে তবে আপনার আইএফএস ব্যবহার করতে হবে :
    • IFS=':'; arrIN=($IN); unset IFS;
  2. যদি মূল স্ট্রিংয়ের স্পেস থাকে এবং ডিলিমিটারটি একটি নতুন লাইন হয় তবে আপনি এটি সহ আইএফএস সেট করতে পারেন :
    • IFS=$'\n'; arrIN=($IN); unset IFS;

84
আমি কেবল যুক্ত করতে চাই: এটি সবার মধ্যে সহজতম, আপনি ray r আরিন [1] with (অবশ্যই জিরো থেকে শুরু করে) এর মাধ্যমে অ্যারে উপাদানগুলি অ্যাক্সেস করতে পারেন
ওজ 123

26
এটি খুঁজে পেয়েছে: একটি within {within এর মধ্যে একটি ভেরিয়েবল পরিবর্তন করার কৌশলটি 'প্যারামিটার সম্প্রসারণ' হিসাবে পরিচিত।
কমোডোডেভ

22
না, আমি মনে করি না যে এই স্থানগুলি উপস্থিত থাকলে এটি কাজ করে ... এটি ',' তে '' রূপান্তর করে এবং একটি স্পেস-বিভাজিত অ্যারে তৈরি করে।
ইথান

12
খুব সংক্ষিপ্ত, তবে সাধারণ ব্যবহারের জন্য সতর্কতা রয়েছে : শেলটি স্ট্রিংয়ের সাথে শব্দ বিভাজন এবং প্রসারণ প্রয়োগ করে, যা অনাকাঙ্ক্ষিত হতে পারে; এটি দিয়ে চেষ্টা করুন। IN="bla@some.com;john@home.com;*;broken apart"। সংক্ষেপে: যদি আপনার টোকেনগুলিতে এমবেডড স্পেস এবং / অথবা অক্ষর থাকে তবে এই পদ্ধতির বিভাজন ঘটবে। যেমন *বর্তমান ফোল্ডারে টোকেন ম্যাচ ফাইলের নামগুলি তৈরি করতে ঘটে।
mklement0

53
এটি অন্যান্য কারণে খারাপ দৃষ্টিভঙ্গি: উদাহরণস্বরূপ, যদি আপনার স্ট্রিংটি থাকে ;*;তবে *এটি বর্তমান ডিরেক্টরিতে ফাইলের নামের তালিকায় প্রসারিত হবে। -1
চার্লস ডাফি

249

আপনি যদি তাৎক্ষণিকভাবে তাদের প্রক্রিয়া করতে আপত্তি না করেন তবে আমি এটি করতে পছন্দ করি:

for i in $(echo $IN | tr ";" "\n")
do
  # process
done

আপনি অ্যারের সূচনা করতে এই ধরণের লুপটি ব্যবহার করতে পারেন তবে এটি করার সহজ উপায় সম্ভবত রয়েছে। আশা করি এটি সাহায্য করবে, যদিও।


আপনার আইএফএস উত্তরটি রাখা উচিত ছিল। এটি আমাকে এমন কিছু শিখিয়েছিল যা আমি জানতাম না এবং এটি অবশ্যই একটি অ্যারে তৈরি করেছিল, যদিও এটি কেবল একটি সস্তা বিকল্প করে।
ক্রিস লুটজ

আমি দেখি. হ্যাঁ আমি এই নিরীহ পরীক্ষা-নিরীক্ষা করে দেখতে পাচ্ছি, প্রতিবার আমি জিনিসগুলির উত্তর দেওয়ার চেষ্টা করছি নতুন জিনিস শিখতে। আমি # ব্যাশ আইআরসি প্রতিক্রিয়া এবং মোছা ছাড়াইয়ের উপর ভিত্তি করে স্টাফ সম্পাদনা করেছি :)
জোহানেস স্কাউব - লিটব

33
-1, আপনি স্পষ্টতই ওয়ার্ডস্প্লিটিং সম্পর্কে সচেতন নন, কারণ এটি আপনার কোডে দুটি বাগ প্রবর্তন করছে। একটি হ'ল আপনি যখন উদ্ধৃতি দিবেন না the IN এবং অন্যটি যখন আপনি একটি নতুন লাইন ভান করেন তখন কেবল শব্দ বিভাজনে ব্যবহৃত ডিলিমিটার। আপনি প্রতিটি লাইন নয়, প্রতিটি লাইন ইন-এর মাধ্যমে পুনরাবৃত্তি করছেন এবং নির্ধারিতভাবে প্রতিটি সেমিকোলন দ্বারা বিসর্জনিত প্রতিটি উপাদানকে নির্ধারণ করে না, যদিও এটির মতো কাজ করার মতো পার্শ্ব-প্রতিক্রিয়া রয়েছে বলে মনে হয়।
lhunath

3
আপনি এটিকে "$ IN" | প্রতিধ্বনিতে পরিবর্তন করতে পারেন ট্র ' '। n' | ADDY পড়ার সময়; do # প্রক্রিয়া "$ ADDY"; তাকে ভাগ্যবান করার জন্য করা হয়েছে, আমি মনে করি :) দ্রষ্টব্য যে এটি কাঁটাচামচ হবে, এবং আপনি লুপের মধ্যে থেকে বাহ্যিক ভেরিয়েবলগুলি পরিবর্তন করতে পারবেন না (এজন্য আমি <<< "$ IN" বাক্য
গঠনটি ব্যবহার করেছি

8
মন্তব্যে বিতর্কটির সংক্ষিপ্তসার হিসাবে: সাধারণ ব্যবহারের জন্য গুহাত : শেলটি স্ট্রিংয়ে শব্দ বিভাজন এবং প্রসারণ প্রয়োগ করে, যা অনাকাঙ্ক্ষিত হতে পারে; এটি দিয়ে চেষ্টা করুন। IN="bla@some.com;john@home.com;*;broken apart"। সংক্ষেপে: যদি আপনার টোকেনগুলিতে এমবেডড স্পেস এবং / অথবা অক্ষর থাকে তবে এই পদ্ধতির বিভাজন ঘটবে। যেমন *বর্তমান ফোল্ডারে টোকেন ম্যাচ ফাইলের নামগুলি তৈরি করতে ঘটে।
mklement0

202

সামঞ্জস্যপূর্ণ উত্তর

এটি করার বিভিন্ন উপায় রয়েছে

তবে, এটি প্রথমে লক্ষ্য করা গুরুত্বপূর্ণ যে bashএর মধ্যে অনেকগুলি বিশেষ বৈশিষ্ট্য রয়েছে (তথাকথিত বাশিজম ) যা অন্য কোনও ক্ষেত্রে কাজ করবে না

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

উদাহরণস্বরূপ: আমার ডেবিয়ান জিএনইউ / লিনাক্সে , একটি মানক শেল বলা হয়; আমি এমন অনেক লোককে জানি যারা নামক একটি শেল ব্যবহার করতে পছন্দ করে; এবং একটি বিশেষ সরঞ্জামও বলা হয় তার নিজের শেল দোভাষী সাথে ()।

অনুরোধ করা স্ট্রিং

উপরের প্রশ্নের বিভাজনে স্ট্রিংটি হ'ল:

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),, , এবং এর :

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>]

আনন্দ কর!


15
#, ##, %, এবং %%বদল কি আইএমও স্মরণ করার জন্য একটি সহজ ব্যাখ্যা (কতটা তারা মুছতে জন্য) আছে: #এবং %সম্ভাব্য সবচেয়ে কম ম্যাচিং স্ট্রিং মুছুন এবং ##এবং %%দীর্ঘতম সম্ভব মুছে দিন।
স্কোর_উন্ডার

1
IFS=\; read -a fields <<<"$var"নতুন লাইন ব্যর্থ হলে এবং একটি trailing সম্পর্কে newline যোগ করুন। অন্য সমাধানটি একটি অনুসরণকারী ফাঁকা ক্ষেত্র সরিয়ে দেয়।
আইজাক

শেল ডিলিমিটারটি সবচেয়ে মার্জিত উত্তর, পিরিয়ড।
এরিক চেন

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

হ্যাঁ, একটি লুপে:for sep in "#" "ł" "@" ; do ... var="${var#*$sep}" ...
এফ হৌরি

183

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

এই নির্দিষ্ট উদাহরণটিকে বাশ স্ক্রিপ্ট অ্যারেতে বিভক্ত করার ক্ষেত্রে trসম্ভবত আরও দক্ষ, তবে cutএটি ব্যবহার করা যেতে পারে, এবং আপনি যদি মাঝখানে থেকে নির্দিষ্ট ক্ষেত্রগুলি টানতে চান তবে আরও কার্যকর।

উদাহরণ:

$ echo "bla@some.com;john@home.com" | cut -d ";" -f 1
bla@some.com
$ echo "bla@some.com;john@home.com" | cut -d ";" -f 2
john@home.com

আপনি এটিকে স্পষ্টতই একটি লুপে রেখে দিতে পারেন এবং প্রতিটি ক্ষেত্রকে স্বাধীনভাবে টানতে -f পরামিতিটি পুনরায় করতে পারেন।

আপনি যখন সারিগুলির মতো সীমিত লগ ফাইলটি পান তখন এটি আরও কার্যকর হয়:

2015-04-27|12345|some action|an attribute|meta data

cutcatএই ফাইলটিতে সক্ষম হতে খুব সহজ এবং আরও প্রক্রিয়াকরণের জন্য একটি নির্দিষ্ট ক্ষেত্র নির্বাচন করুন।


6
কুডোস ব্যবহারের জন্য cut, এটি কাজের সঠিক সরঞ্জাম! এই শেল হ্যাকগুলির তুলনায় অনেকগুলি সাফ হয়েছে।
মিস্টারমিয়াগি

4
এই পদ্ধতিটি কেবল তখনই কাজ করবে যদি আপনি আগাম উপাদানগুলির সংখ্যা জানেন; আপনার চারপাশে আরও কিছু যুক্তি প্রদর্শন করার দরকার আছে। এটি প্রতিটি উপাদানগুলির জন্য একটি বাহ্যিক সরঞ্জাম চালায়।
uli42

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

আইডি এবং পিআইডি টানার জন্য খুব দরকারী, যেমন
মিলোস গ্রুজিক

এই উত্তরটি অর্ধেক পৃষ্ঠার নিচে স্ক্রোল করার উপযুক্ত :)
Gucu112

124

এটি আমার পক্ষে কাজ করেছে:

string="1;2"
echo $string | cut -d';' -f1 # output is 1
echo $string | cut -d';' -f2 # output is 2

1
যদিও এটি কেবলমাত্র একটি একক চরিত্রের ডিলিমিটারের সাথে কাজ করে, সেটাই ওপি খুঁজছিল (সেমিকোলন দ্বারা সীমাবদ্ধ রেকর্ডস)।
গাইপ্যাডক

@ আশোক দ্বারা প্রায় চার বছর আগে উত্তর দেওয়া হয়েছিল এবং আরও এক বছরেরও বেশি আগে @ ডগডাব্লু দ্বারা আরও উত্তর দিয়েছিলেন আপনার উত্তরের চেয়েও বেশি with অন্যের চেয়ে আলাদা সমাধান পোস্ট করুন '।
MAChitgarha

90

এই পদ্ধতির সম্পর্কে কীভাবে:

IN="bla@some.com;john@home.com" 
set -- "$IN" 
IFS=";"; declare -a Array=($*) 
echo "${Array[@]}" 
echo "${Array[0]}" 
echo "${Array[1]}" 

সূত্র


7
+1 ... তবে আমি ভেরিয়েবলটির নাম "অ্যারে" রাখব না ... পোষা প্রাণীর ধারণা আমি অনুমান করি। ভাল সমাধান।
ইজমির রামিরেজ

14
+1 ... তবে "সেট" এবং ঘোষণা -a অপ্রয়োজনীয়। আপনি ঠিক মাত্র ব্যবহার করতে পারতেনIFS";" && Array=($IN)
আতা

+1 শুধুমাত্র একটি পার্শ্ব নোট: পুরানো আইএফএস রাখা এবং তারপরে এটি পুনরুদ্ধার করা বাঞ্ছনীয় হওয়া উচিত নয়? (যেমন তার সম্পাদনা3 তে স্টেফানবি দেখিয়েছেন) লোকেরা এখানে অবতরণ করছে (কখনও কখনও কেবল সমাধানটি অনুলিপি করে পেস্ট করে থাকে) এ সম্পর্কে ভাবতে পারে না
লুকা বোররিওন

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

1
ব্যবহারের সুপারিশ $'...': IN=$'bla@some.com;john@home.com;bet <d@\ns* kl.com>'। তারপরে echo "${Array[2]}"নতুন লাইনের সাথে একটি স্ট্রিং প্রিন্ট করবে। set -- "$IN"এই ক্ষেত্রে এছাড়াও প্রয়োজনীয়। হ্যাঁ, গ্লোব সম্প্রসারণ রোধ করতে, সমাধানটিতে অন্তর্ভুক্ত করা উচিত set -f
জন_ ওয়েস্ট

78

আমি মনে করি আপনার সমস্যা সমাধানের জন্য AWK হ'ল সেরা এবং দক্ষ আদেশ। AWK প্রায় প্রতিটি লিনাক্স বিতরণে ডিফল্টরূপে অন্তর্ভুক্ত থাকে।

echo "bla@some.com;john@home.com" | awk -F';' '{print $1,$2}'

দিতে হবে

bla@some.com john@home.com

অবশ্যই আপনার প্রতিটি ইমেল ঠিকানা সন্ত্রাস মুদ্রণ ক্ষেত্রটির নতুন সংজ্ঞা দিয়ে সঞ্চয় করতে পারেন।


3
বা এমনকি আরও সহজ: প্রতিধ্বনি "bla@some.com; jnn@home.com" | awk 'BEGIN {RS = ";"} {মুদ্রণ}'
জারো

@ জারো যখন আমার কমা নিয়ে একটি স্ট্রিং ছিল এবং এটির লাইনে পুনরায় ফর্ম্যাট করার প্রয়োজন ছিল এটি আমার পক্ষে পুরোপুরি কাজ করেছিল। ধন্যবাদ।
অ্যাকোয়ারেল 21

এটি এই দৃশ্যে কাজ করেছে -> "প্রতিধ্বনি" $ SPLIT_0 "| awk -F 'inode =' '{মুদ্রণ $ 1}'"! অক্ষর (";") এর পরিবর্তে অ্যাট্রিংস ("inode =") ব্যবহার করার চেষ্টা করার সময় আমার সমস্যা হয়েছিল। Ar 1, $ 2, $ 3, $ 4 একটি অ্যারেতে পজিশন হিসাবে সেট করা আছে! যদি অ্যারে সেট করার কোনও উপায় থাকে ... আরও ভাল! ধন্যবাদ!
এডুয়ার্ডো লুসিও

@EduardoLucio, আমি চিন্তা করছি সম্পর্কে হয়তো আপনি প্রথমে আপনার বিভেদক প্রতিস্থাপন করতে পারেন inode=মধ্যে ;উদাহরণস্বরুপ sed -i 's/inode\=/\;/g' your_file_to_process, তারপর সংজ্ঞায়িত -F';'যখন আবেদন awk, আশা যে আপনার সাহায্য করতে পারেন।
টং

66
echo "bla@some.com;john@home.com" | sed -e 's/;/\n/g'
bla@some.com
john@home.com

4
-1 স্ট্রিংয়ের ফাঁকা জায়গা থাকলে কী হবে? উদাহরণস্বরূপ IN="this is first line; this is second line" arrIN=( $( echo "$IN" | sed -e 's/;/\n/g' ) )এই ক্ষেত্রে 8 টি উপাদানের অ্যারে তৈরি করা হবে (প্রতিটি শব্দের স্থানের জন্য পৃথক পৃথক প্রতিটি উপাদান) পরিবর্তে 2 (প্রতিটি লাইনের অর্ধ কোলনের জন্য পৃথক একটি উপাদান)
লুকা বোররিওন

3
@ লুকা নো সিড স্ক্রিপ্ট ঠিক দুটি লাইন তৈরি করে। আপনার জন্য একাধিক এন্ট্রি তৈরি করে যখন আপনি এটি ব্যাশ অ্যারেতে রাখেন (যা ডিফল্টরূপে সাদা স্পেসে বিভক্ত হয়)
লোথার

ঠিক এটিই মূল বিষয়: ওপিকে এটি লুপ করার জন্য একটি অ্যারেতে এন্ট্রিগুলি সঞ্চয় করতে হবে, আপনি তাঁর সম্পাদনাগুলিতে দেখতে পাচ্ছেন। আমি মনে করি আপনার (উত্তম) উত্তরটি arrIN=( $( echo "$IN" | sed -e 's/;/\n/g' ) )তা অর্জনের জন্য ব্যবহার করতে উল্লেখ করা যায় নি , এবং IFS=$'\n'ভবিষ্যতে যারা এখানে অবতরণ করেছেন এবং তাদের জন্য স্পেসযুক্ত স্ট্রিং বিভক্ত করতে হবে তাদের জন্য আইএফএস পরিবর্তন করার পরামর্শের পরামর্শ দিয়েছেন । (এবং পরে এটি পুনরুদ্ধার করতে)। :)
লুকা বোররিওন

1
@ লুকা ভাল পয়েন্ট। তবে আমি যখন উত্তরটি লিখেছিলাম তখন অ্যারে নিয়োগ প্রাথমিক প্রশ্নের মধ্যে ছিল না
লোথার

65

এটিও কাজ করে:

IN="bla@some.com;john@home.com"
echo ADD1=`echo $IN | cut -d \; -f 1`
echo ADD2=`echo $IN | cut -d \; -f 2`

সতর্কতা অবলম্বন করুন, এই সমাধানটি সর্বদা সঠিক নয়। যদি আপনি কেবল "বেল @some.com" পাস করেন তবে এটি এডিডি 1 এবং এডিডি 2 উভয়কেই বরাদ্দ করবে।


1
: আপনি উল্লেখ সমস্যা এড়ানোর -s ব্যবহার করতে পারেন superuser.com/questions/896800/... ; যদি না -s বিকল্প এছাড়াও, কোন লাইন যে কোন বিভেদক অক্ষর আছে ছাপি "-f, --fields = তালিকা শুধুমাত্র এই ক্ষেত্র নির্বাচন "
fersarr

34

ড্যারনের উত্তরকে আলাদাভাবে গ্রহণ করা , আমি এটি এটিই করি:

IN="bla@some.com;john@home.com"
read ADDR1 ADDR2 <<<$(IFS=";"; echo $IN)

আমার মনে হয় এটা হয়! উপরের কমান্ডগুলি চালনা করুন এবং তারপরে "প্রতিধ্বনি $ ADDR1 ... $ ADDR2" এবং আমি "bla@some.com ... john@home.com" আউটপুট
পাই

1
এটি আমার জন্য সত্যই ভাল কাজ করেছে ... আমি এটি স্ট্রিংগুলির একটি অ্যারেতে ইমেট্রেট করতে ব্যবহৃত হয়েছিল যার মধ্যে মাইকিকিলেড্প ব্যবহারের জন্য কমা বিচ্ছিন্ন ডিবি, সার্ভার, পোর্ট ডেটা রয়েছে।
নিক

5
ডায়াগনোসিস: IFS=";"অ্যাসাইনমেন্টটি কেবল $(...; echo $IN)সাব - শেইলে বিদ্যমান ; এ কারণেই কিছু পাঠক (আমাকে সহ) প্রাথমিকভাবে ভাবেন যে এটি কার্যকর হবে না। আমি ধরে নিয়েছি যে সমস্ত $ IN এডিডিআর 1 দ্বারা স্লিপড হয়ে যাচ্ছে। তবে নিকজ্ব সঠিক; এটা কাজ করে। কারণটি হ'ল echo $INকমান্ডটি $ আইএফএসের বর্তমান মান ব্যবহার করে তার যুক্তিগুলি পার্স করে, তবে তারপরে $ আইএফএসের সেটিং নির্বিশেষে স্পেস ডিলিমিটার ব্যবহার করে স্টাডআউট করার প্রতিধ্বনি দেয়। সুতরাং নেট প্রভাবটি যেমন কল করেছে read ADDR1 ADDR2 <<< "bla@some.com john@home.com"(নোট করুন স্থানটি পৃথক নয়; -বিচ্ছিন্ন)।
সন্দেহজনক জিম

1
এটি স্পেস এবং নিউলাইনগুলিতে ব্যর্থ হয় এবং অদৈর্ঘ্য পরিবর্তনশীল প্রসারণ সহ ওয়াইল্ডকার্ডগুলি প্রসারিত *করে echo $IN
আইজাক

আমি এই সমাধানটি সত্যিই পছন্দ করি। এটি কেন কাজ করে তার একটি বিবরণ খুব দরকারী হবে এবং এটি আরও ভাল সামগ্রিক উত্তর হিসাবে তৈরি করবে।
মাইকেল গসকিল

32

বাশ-এ, একটি বুলেট প্রুফ উপায়, এটি যদি আপনার ভেরিয়েবলে নতুন লাইন থাকে তবে তা কাজ করবে:

IFS=';' read -d '' -ra array < <(printf '%s;\0' "$in")

দেখুন:

$ in=$'one;two three;*;there is\na newline\nin this field'
$ IFS=';' read -d '' -ra array < <(printf '%s;\0' "$in")
$ declare -p array
declare -a array='([0]="one" [1]="two three" [2]="*" [3]="there is
a newline
in this field")'

এটি কাজ করার কৌশলটি হ'ল খালি ডিলিমিটার সহ (ডিলিমিটার) -dবিকল্পটি ব্যবহার করা read, যাতে readএটি খাওয়ানো সমস্ত কিছুই পড়তে বাধ্য হয়। এবং আমরা readভেরিয়েবলের ঠিক কন্টেন্টটি দিয়ে ফিড করি in, এতে কোনও নতুন লাইনের ধন্যবাদ নেই printf। উল্লেখ্য যে printfস্ট্রিংটি readএকটি অনুবর্তিত ডিলিমিটার রয়েছে তা নিশ্চিত করার জন্য আমরা ডিলিমিটারটিও রেখেছি। এটি ছাড়া, readসম্ভাব্য ট্র্যাকিং ফাঁকা ক্ষেত্রগুলি ছাঁটাই করবে:

$ in='one;two;three;'    # there's an empty field
$ IFS=';' read -d '' -ra array < <(printf '%s;\0' "$in")
$ declare -p array
declare -a array='([0]="one" [1]="two" [2]="three" [3]="")'

ট্রেইলিং খালি মাঠটি সংরক্ষণ করা হয়েছে।


Bas≥4.4 এর জন্য আপডেট

4.4 বাশ থেকে, বিল্টিন mapfile(ওরফে readarray) -dএকটি ডিলিমিটার নির্দিষ্ট করার বিকল্পটিকে সমর্থন করে । অতএব আর একটি আধ্যাত্মিক উপায় হ'ল:

mapfile -d ';' -t array < <(printf '%s;' "$in")

5
আমি এটিকে তালিকার বিরল সমাধান হিসাবে খুঁজে পেয়েছি যা \nস্পেস এবং *একসাথে সঠিকভাবে কাজ করে । এছাড়াও, কোন লুপ নেই; অ্যারে ভেরিয়েবল কার্যকর হওয়ার পরে শেলটিতে অ্যাক্সেসযোগ্য (সর্বোচ্চ উত্তোলিত উত্তরের বিপরীতে)। দ্রষ্টব্য, in=$'...'এটি ডাবল উদ্ধৃতি দিয়ে কাজ করে না। আমি মনে করি, এটির আরও বেশি মূল্যায়ন দরকার।
জন_ ওয়েস্ট

28

আপনি যদি অ্যারে ব্যবহার না করেন তবে এই এক লাইনার সম্পর্কে কীভাবে:

IFS=';' read ADDR1 ADDR2 <<<$IN

read -r ...উদাহরণস্বরূপ, ইনপুটটিতে থাকা দুটি অক্ষর "\ t" আপনার ভেরিয়েবলগুলিতে (একটি ট্যাব চরের পরিবর্তে) একই দুটি অক্ষর হিসাবে শেষ হয় তা নিশ্চিত করার জন্য ব্যবহার করে বিবেচনা করুন।
সন্দেহজনক জিম 31'12

-1 এটি এখানে কাজ করছে না (উবুন্টু 12.04)। echo "ADDR1 $ADDR1"\n echo "ADDR2 $ADDR2"আপনার স্নিপেটে যোগ করার ফলে আউটপুট আসবে ADDR1 bla@some.com john@home.com\nADDR2(\ n নতুন লাইন)
লুকা বোরিওনি

এটি সম্ভবত একটি বাগের সাথে জড়িত IFSএবং এখানে স্ট্রিং রয়েছে যা bash৪.৩-এ স্থির হয়েছিল । উদ্ধৃতি $INএটি ঠিক করা উচিত। (তত্ত্ব অনুসারে, $INশব্দ বিভক্ত হওয়ার পরে এটি প্রসারিত হওয়ার পরে গ্লোব্বিংয়ের সাথে সম্পর্কিত নয়, অর্থাত উদ্ধৃতিগুলি অপ্রয়োজনীয় হওয়া উচিত Even.৩-তে যদিও কমপক্ষে একটি বাগ বাকি রয়েছে - রিপোর্ট করা হয়েছে এবং নির্ধারিত হওয়ার জন্য নির্ধারিত রয়েছে - সুতরাং উদ্ধৃতি দেওয়া ভাল থাকবে ধারণা।)
চিপনার

Break ইনতে উদ্ধৃতিযুক্ত এমনকি নতুন লাইনের উপস্থিতি থাকলে এটি ভেঙে যায়। এবং একটি ট্রেলিং নিউলাইন যুক্ত করে।
আইজাক

এটির সাথে একটি সমস্যা এবং আরও অনেক সমাধান হ'ল এটিও ধরে নেয় যে $ IN - তে দুটি দুটি উপাদান রয়েছে বা আপনি দ্বিতীয় এবং পরবর্তী আইটেমগুলিকে ADDR2 এ একসাথে টুকরো টুকরো করতে চান। আমি বুঝতে পারি যে এটি জিজ্ঞাসাটির সাথে মিলিত হয়েছে তবে এটি একটি টাইম বোমা।
স্টিভেন দ্য ইজেলি অ্যাওজেড

21

আইএফএস স্থাপন না করেই

আপনার যদি কেবল একটি কোলন থাকে তবে আপনি এটি করতে পারেন:

a="foo:bar"
b=${a%:*}
c=${a##*:}

তুমি পাবে:

b = foo
c = bar

20

এখানে একটি পরিষ্কার 3-লাইনার রয়েছে:

in="foo@bar;bizz@buzz;fizz@buzz;buzz@woof"
IFS=';' list=($in)
for item in "${list[@]}"; do echo $item; done

যেখানে IFSবিভাজকের উপর ভিত্তি করে সীমিত শব্দগুলি এবং ()একটি অ্যারে তৈরি করতে ব্যবহৃত হয় । তারপর[@] প্রতিটি আইটেমকে পৃথক শব্দ হিসাবে ফেরত দিতে ব্যবহৃত হয়।

এর পরে যদি আপনার কোনও কোড থাকে তবে আপনাকে পুনরুদ্ধার করতে হবে $IFS, যেমন unset IFS


5
$inঅব্যক্ত ব্যবহারের ফলে ওয়াইল্ডকার্ডগুলি প্রসারিত হতে পারে।
আইজাক

10

নিম্নলিখিত বাশ / zsh ফাংশনটি দ্বিতীয় যুক্তির দ্বারা প্রদত্ত ডিলিমেটারে তার প্রথম যুক্তিটি বিভক্ত করে:

split() {
    local string="$1"
    local delimiter="$2"
    if [ -n "$string" ]; then
        local part
        while read -d "$delimiter" part; do
            echo $part
        done <<< "$string"
        echo $part
    fi
}

উদাহরণস্বরূপ, কমান্ড

$ split 'a;b;c' ';'

উৎপাদনের

a
b
c

এই আউটপুট, উদাহরণস্বরূপ, অন্যান্য কমান্ডে পাইপ করা যেতে পারে। উদাহরণ:

$ split 'a;b;c' ';' | cat -n
1   a
2   b
3   c

প্রদত্ত অন্যান্য সমাধানগুলির সাথে তুলনা করে, এটির নিম্নলিখিত সুবিধাগুলি রয়েছে:

  • IFSওভাররিডেন নয়: এমনকি স্থানীয় ভেরিয়েবলগুলির গতিশীল স্কোপিংয়ের কারণে, IFSএকটি লুপের ওভাররাইডিংয়ের ফলে লুপের মধ্য থেকে সঞ্চালিত ফাংশন কলগুলিতে নতুন মানটি ফাঁস হয়।

  • অ্যারে ব্যবহার করা হয় না: অ্যারেতে স্ট্রিং পড়ার readজন্য -aব্যাশ এবং -Azsh এ পতাকা প্রয়োজন ।

যদি ইচ্ছা হয় তবে ফাংশনটি কোনও স্ক্রিপ্টের নীচে দেওয়া যেতে পারে:

#!/usr/bin/env bash

split() {
    # ...
}

split "$@"

1 অক্ষরের চেয়ে বেশি ডিলিমিটারগুলির সাথে কাজ করছে বলে মনে হচ্ছে না: বিভাজন = $ (বিভক্ত "$ বিষয়বস্তু" "ফাইল: //")
ম্যাডপ্রপস

সত্য - থেকে help read:-d delim continue until the first character of DELIM is read, rather than newline
হ্যালি নাস্ট

8

আপনি অনেক পরিস্থিতিতে বিশ্রী আবেদন করতে পারেন

echo "bla@some.com;john@home.com"|awk -F';' '{printf "%s\n%s\n", $1, $2}'

এছাড়াও আপনি এটি ব্যবহার করতে পারেন

echo "bla@some.com;john@home.com"|awk -F';' '{print $1,$2}' OFS="\n"

7

এর মতো সহজ ও স্মার্ট উপায় রয়েছে:

echo "add:sfff" | xargs -d: -i  echo {}

তবে আপনাকে অবশ্যই gnu xargs, BSD xargs cant সমর্থন -d ডিলিম ব্যবহার করতে হবে। আপনি যদি আমার মতো আপেল ম্যাক ব্যবহার করেন। আপনি gnu xargs ইনস্টল করতে পারেন:

brew install findutils

তারপর

echo "add:sfff" | gxargs -d: -i  echo {}

4

এটি করার সহজ উপায় এটি।

spo='one;two;three'
OIFS=$IFS
IFS=';'
spo_array=($spo)
IFS=$OIFS
echo ${spo_array[*]}

4

এখানে কিছু দুর্দান্ত উত্তর রয়েছে (এররেটর এসপি।), তবে অন্যান্য ভাষায় বিভক্ত হওয়ার সাথে কিছু মিলের জন্য - যা মূল প্রশ্নটি আমি বোঝাতে চেয়েছিলাম - আমি এটার উপর স্থিতি রেখেছি:

IN="bla@some.com;john@home.com"
declare -a a="(${IN/;/ })";

এখন ${a[0]}, ${a[1]}ইত্যাদি, আপনার প্রত্যাশা মতো। ${#a[*]}পদ সংখ্যা জন্য ব্যবহার করুন । বা অবশ্যই পুনরাবৃত্তি করতে:

for i in ${a[*]}; do echo $i; done

গুরুত্বপূর্ণ তথ্য:

এটি এমন পরিস্থিতিতে কাজ করে যেখানে উদ্বিগ্ন হওয়ার মতো জায়গাগুলি নেই, যা আমার সমস্যার সমাধান করেছে, তবে আপনার সমাধান করতে পারে না। সেক্ষেত্রে $IFSসমাধান (গুলি) নিয়ে যান ।


দুটিরও INবেশি ইমেল ঠিকানা থাকাতে কাজ করে না। দয়া করে প্যালিনড্রামের উত্তরে
ওলিব্রে

${IN//;/ }এটি আরও দুটি মানের সাথে কাজ করতে আরও ভাল ব্যবহার (ডাবল স্ল্যাশ)। সাবধান যে কোনও ওয়াইল্ডকার্ড ( *?[) প্রসারিত হবে। এবং একটি অনুসরণকারী খালি ক্ষেত্রটি বাতিল করা হবে।
আইজাক

3
IN="bla@some.com;john@home.com"
IFS=';'
read -a IN_arr <<< "${IN}"
for entry in "${IN_arr[@]}"
do
    echo $entry
done

আউটপুট

bla@some.com
john@home.com

সিস্টেম: উবুন্টু 12.04.1


আইএফএস readএখানে নির্দিষ্ট প্রসঙ্গে সেট করা হচ্ছে না এবং তাই এটি কোডের বাকী অংশগুলিকে বিপর্যস্ত করতে পারে, যদি থাকে তবে।
কোডফোরস্টার

2

যদি জায়গা না থাকে তবে কেন এটি হবে না?

IN="bla@some.com;john@home.com"
arr=(`echo $IN | tr ';' ' '`)

echo ${arr[0]}
echo ${arr[1]}

2

অ্যারে setলোড করতে অন্তর্নির্মিতটি ব্যবহার করুন $@:

IN="bla@some.com;john@home.com"
IFS=';'; set $IN; IFS=$' \t\n'

তারপরে, পার্টি শুরু করা যাক:

echo $#
for a; do echo $a; done
ADDR1=$1 ADDR2=$2

set -- $INড্যাশ দিয়ে শুরু করে "$ IN" দিয়ে কিছু সমস্যা এড়াতে আরও ভাল ব্যবহার । তবুও, উদাত্ত প্রসারণটি $INওয়াইল্ডকার্ডগুলি প্রসারিত করবে ( *?[)।
আইজাক

2

দুটি বোর্ন-ইশ বিকল্প যেখানে বাশ অ্যারেগুলির প্রয়োজন হয় না:

কেস 1 : এটি সুন্দর এবং সহজ রাখুন: রেকর্ড-বিভাজক হিসাবে একটি নিউলাইন ব্যবহার করুন ... যেমন।

IN="bla@some.com
john@home.com"

while read i; do
  # process "$i" ... eg.
    echo "[email:$i]"
done <<< "$IN"

দ্রষ্টব্য: এই প্রথম ক্ষেত্রে কোনও উপ-প্রক্রিয়া তালিকা ম্যানিপুলেশন সহায়তা করার জন্য জোর করা হয় না।

আইডিয়া: সম্ভবত এটি এনএল ব্যাপকভাবে অভ্যন্তরীণভাবে ব্যবহারের পক্ষে মূল্যবান এবং চূড়ান্ত ফলাফলটি বাহ্যিকভাবে উত্পাদনের সময় কেবল কোনও আলাদা আরএসে রূপান্তরিত ।

কেস 2 : একটি ";" ব্যবহার রেকর্ড বিভাজক হিসাবে ... যেমন

NL="
" IRS=";" ORS=";"

conv_IRS() {
  exec tr "$1" "$NL"
}

conv_ORS() {
  exec tr "$NL" "$1"
}

IN="bla@some.com;john@home.com"
IN="$(conv_IRS ";" <<< "$IN")"

while read i; do
  # process "$i" ... eg.
    echo -n "[email:$i]$ORS"
done <<< "$IN"

উভয় ক্ষেত্রে লুপটির মধ্যে একটি উপ-তালিকা তৈরি করা যেতে পারে লুপটি শেষ হওয়ার পরে অবিচ্ছিন্ন। মেমরিতে তালিকাগুলি হেরফের করার পরিবর্তে ফাইলগুলিতে তালিকাগুলি সংরক্ষণ করার সময় এটি দরকারী। {পিএস শান্ত থাকুন এবং বি-) চালিয়ে যান}


2

ইতিমধ্যে সরবরাহ করা চমত্কার উত্তরগুলি বাদে, যদি এটি ব্যবহার করার জন্য বিবেচনা করা যেতে পারে এমন ডেটা মুদ্রণের বিষয় হয় awk:

awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]\n", $i)}' <<< "$IN"

এটি ক্ষেত্রের বিভাজকটিকে সেট করে ;, যাতে এটি ক্ষেত্রের মধ্য দিয়ে একটি forলুপ দিয়ে লুপ করে এবং সেই অনুযায়ী মুদ্রণ করতে পারে।

পরীক্ষা

$ IN="bla@some.com;john@home.com"
$ awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]\n", $i)}' <<< "$IN"
> [bla@some.com]
> [john@home.com]

অন্য ইনপুট সহ:

$ awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]\n", $i)}' <<< "a;b;c   d;e_;f"
> [a]
> [b]
> [c   d]
> [e_]
> [f]

2

অ্যান্ড্রয়েড শেল-এ, বেশিরভাগ প্রস্তাবিত পদ্ধতি কেবল কাজ করে না:

$ IFS=':' read -ra ADDR <<<"$PATH"                             
/system/bin/sh: can't create temporary file /sqlite_stmt_journals/mksh.EbNoR10629: No such file or directory

কাজ কি:

$ for i in ${PATH//:/ }; do echo $i; done
/sbin
/vendor/bin
/system/sbin
/system/bin
/system/xbin

যেখানে //বিশ্বব্যাপী প্রতিস্থাপনের অর্থ।


1
Ails PATH এর কোনও অংশে ফাঁকা স্থান (বা নিউলাইন) থাকলে ব্যর্থ। ওয়াইল্ডকার্ডগুলিও বিস্তৃত করে (তারকাচিহ্ন *, প্রশ্ন চিহ্ন? এবং বন্ধনীগুলি […])।
আইজাক

2
IN='bla@some.com;john@home.com;Charlie Brown <cbrown@acme.com;!"#$%&/()[]{}*? are no problem;simple is beautiful :-)'
set -f
oldifs="$IFS"
IFS=';'; arrayIN=($IN)
IFS="$oldifs"
for i in "${arrayIN[@]}"; do
echo "$i"
done
set +f

আউটপুট:

bla@some.com
john@home.com
Charlie Brown <cbrown@acme.com
!"#$%&/()[]{}*? are no problem
simple is beautiful :-)

ব্যাখ্যা: প্রথম বন্ধনীর সাহায্যে অ্যাসাইনমেন্ট () সেমিকোলন বিচ্ছিন্ন তালিকে একটি অ্যারেতে রূপান্তর করে তবে আপনি যদি সঠিক আইএফএস করার সময় এটি করেন। স্ট্যান্ডার্ড ফর লুপ স্বাভাবিকভাবে সেই অ্যারেতে পৃথক আইটেম পরিচালনা করে। লক্ষ্য করুন যে IN ভেরিয়েবলের জন্য প্রদত্ত তালিকার অবশ্যই "হার্ড" উদ্ধৃত হওয়া আবশ্যক, যা একক টিক্স সহ।

আইএফএস সংরক্ষণ করতে হবে এবং পুনরুদ্ধার করতে হবে যেহেতু বাশ কোনও অ্যাসাইনমেন্টকে কমান্ডের মতো করে না। একটি বিকল্প workaround হ'ল একটি ফাংশনের ভিতরে অ্যাসাইনমেন্টটি মোড়ানো এবং পরিবর্তিত আইএফএসের সাহায্যে সেই ফাংশনটি কল করা। সেক্ষেত্রে আইএফএসের পৃথক সঞ্চয় / পুনরুদ্ধারের প্রয়োজন হয় না। এটি নির্দেশ করার জন্য "বাইজ" এর জন্য ধন্যবাদ।


!"#$%&/()[]{}*? are no problemভাল ... বেশ নয়: []*?গ্লোব অক্ষর। তাহলে এই ডিরেক্টরি এবং ফাইলটি তৈরি করার কী আছে: `mkdir '!" # $% &'; টাচ '! "# $% & / () [] {You আপনাকে হাফাহাহা করেছে - কোনও সমস্যা নেই' এবং আপনার কমান্ড চালাচ্ছে? সাধারণটি সুন্দর হতে পারে তবে এটি যখন ভেঙে যায় তখন এটি ভেঙে যায়।
gniourf_gniourf

@gniourf_gniourf স্ট্রিংটি একটি ভেরিয়েবলে সংরক্ষণ করা হয়। দয়া করে আসল প্রশ্নটি দেখুন।
আজাস্কেল

1
@જાাস্কেল আপনি আমার মন্তব্যটি পুরোপুরি বুঝতে পারেন নি। একটি স্ক্র্যাচ ডিরেক্টরির মধ্যে যান এবং এই কমান্ডটি ব্যবহার করুন: mkdir '!"#$%&'; touch '!"#$%&/()[]{} got you hahahaha - are no problem'। তারা কেবল একটি ডিরেক্টরি এবং একটি ফাইল তৈরি করবে, অদ্ভুত সন্ধানের নাম সহ, আমাকে অবশ্যই স্বীকার করতে হবে। তারপর সঠিক সঙ্গে আপনার কমান্ড সঞ্চালন করুন INআপনি দিয়েছেন: IN='bla@some.com;john@home.com;Charlie Brown <cbrown@acme.com;!"#$%&/()[]{}*? are no problem;simple is beautiful :-)'। আপনি দেখতে পাবেন যে আপনি যে আউটপুট আশা করেছেন তা পাবেন না। কারণ আপনি আপনার স্ট্রিংকে বিভক্ত করতে পথের নাম প্রসার সাপেক্ষে একটি পদ্ধতি ব্যবহার করছেন।
gniourf_gniourf

এই প্রকট যে অক্ষর *, ?, [...]এবং এমনকি, যদি extglobসেট করা থাকে, !(...), @(...), ?(...), +(...) হয় এই পদ্ধতি সঙ্গে সমস্যা!
gniourf_gniourf

1
@gniourf_gniourf বিশ্বব্যাপী বিস্তারিত মন্তব্যের জন্য ধন্যবাদ। আমি গ্লোব্বিং বন্ধ করার জন্য কোডটি সামঞ্জস্য করেছি। আমার বক্তব্যটি কেবল এটি দেখানোর জন্য ছিল যে বরং সরল অ্যাসাইনমেন্টটি বিভাজন কাজ করতে পারে।
আজাস্কেল

1

ওকে বলছি!

আমার উত্তর এখানে!

DELIMITER_VAL='='

read -d '' F_ABOUT_DISTRO_R <<"EOF"
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.4 LTS"
NAME="Ubuntu"
VERSION="14.04.4 LTS, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 14.04.4 LTS"
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
EOF

SPLIT_NOW=$(awk -F$DELIMITER_VAL '{for(i=1;i<=NF;i++){printf "%s\n", $i}}' <<<"${F_ABOUT_DISTRO_R}")
while read -r line; do
   SPLIT+=("$line")
done <<< "$SPLIT_NOW"
for i in "${SPLIT[@]}"; do
    echo "$i"
done

এই পদ্ধতিরটি কেন আমার পক্ষে "সেরা"?

দুটি কারণে:

  1. আপনার পালানোর দরকার নেই ডিলিমিটার ;
  2. ফাঁকা জায়গা নিয়ে আপনার সমস্যা হবে না । অ্যারেতে মানটি আলাদা হয়ে যাবে!

[] এর


এফওয়াইআই, /etc/os-releaseএবং /etc/lsb-releaseএটি উত্সর্গীকৃত হতে বোঝানো হয়েছে, এবং পার্স করা হয়নি। সুতরাং আপনার পদ্ধতি সত্যিই ভুল। তদুপরি, আপনি একটি ডিলিমিটারে স্ট্রিং স্পিল্টিং
gniourf_gniourf

0

স্ট্রিংকে ';' দ্বারা বিভক্ত করার জন্য একটি ওয়ান-লাইনার; একটি অ্যারে মধ্যে হয়:

IN="bla@some.com;john@home.com"
ADDRS=( $(IFS=";" echo "$IN") )
echo ${ADDRS[0]}
echo ${ADDRS[1]}

এটি কেবলমাত্র সাবএলে আইএফএস সেট করে, তাই এর মান সংরক্ষণ এবং পুনরুদ্ধার করার জন্য আপনাকে চিন্তা করতে হবে না।


-1 এটি এখানে কাজ করে না (উবুন্টু 12.04)। এটিতে সর্বমোট মান সহ কেবল প্রথম প্রতিধ্বনি মুদ্রিত হয়, যখন দ্বিতীয়টি খালি থাকে। যদি আপনি "0:" e {ADDRS [0]} \ n প্রতিধ্বনি "1": "$ {ADDRS [1] put রাখেন তবে আউটপুটটি 0: bla@some.com;john@home.com\n 1:(new n নতুন লাইন)
লুকা বোররিওন

1
এই ধারণার একটি কার্যকরী বিকল্পের জন্য দয়া করে নিকজ্বের জবাবটি দেখুন stackoverflow.com/a/6583589/1032370
লুকা বোররিওন

1
-১, ১. আইএফএস সেই সাবশেলে সেট করা হচ্ছে না (এটি "প্রতিধ্বনি" -র পরিবেশে পৌঁছে যাচ্ছে যা একটি বিল্টিন, সুতরাং যাইহোক কিছুই হচ্ছে না)। 2. $INএর উদ্ধৃতি দেওয়া হয়েছে সুতরাং এটি আইএফএস বিভাজনের বিষয় নয়। ৩. প্রক্রিয়া প্রতিস্থাপনটি হোয়াইটস্পেসের মাধ্যমে বিভক্ত করা হয় তবে এটি মূল ডেটাটিকে দূষিত করতে পারে।
স্কোর_উন্ডার

0

সম্ভবত সবচেয়ে মার্জিত সমাধান নয়, তবে কাজ করে *এবং স্পেস করে:

IN="bla@so me.com;*;john@home.com"
for i in `delims=${IN//[^;]}; seq 1 $((${#delims} + 1))`
do
   echo "> [`echo $IN | cut -d';' -f$i`]"
done

আউটপুট

> [bla@so me.com]
> [*]
> [john@home.com]

অন্যান্য উদাহরণ (প্রারম্ভিক এবং শেষে বিস্ময়কর):

IN=";bla@so me.com;*;john@home.com;"
> []
> [bla@so me.com]
> [*]
> [john@home.com]
> []

মূলত প্রতিটি ছাড়া অন্য চরিত্র সরিয়ে ফেলা ;উপার্জন delimsযেমন। ;;;। তারপরে এটি গণনা অনুসারে forলুপ থেকে 1যায় । চূড়ান্ত পদক্ষেপটি ব্যবহার করে নিরাপদে অংশটি পাওয়া ।number-of-delimiters${#delims}$icut

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