বাশ শেলের কমপক্ষে একটি স্থান দ্বারা পৃথক এক স্ট্রিংকে একাধিক স্ট্রিংগুলিতে কীভাবে বিভক্ত করা যায়?


224

আমার দু'জনের মধ্যে কমপক্ষে একটি স্থান সহ অনেকগুলি শব্দযুক্ত স্ট্রিং রয়েছে। আমি কীভাবে স্ট্রিংটিকে পৃথক কথায় বিভক্ত করতে পারি যাতে আমি সেগুলির মধ্য দিয়ে লুপ করতে পারি?

স্ট্রিংটি আর্গুমেন্ট হিসাবে পাস করা হয়। যেমন ${2} == "cat cat file"। আমি কিভাবে এটি লুপ করতে পারি?

এছাড়াও, আমি স্ট্রিংয়ের ফাঁকা স্থান রয়েছে কিনা তা আমি কীভাবে পরীক্ষা করতে পারি?


1
এ কেমন শেল? বাশ, সেমিডি.এক্সি, পাওয়ারশেল ...?
আলেক্সি শিরিদভ

আপনার কি কেবল লুপ করা দরকার (উদাহরণস্বরূপ প্রতিটি শব্দের জন্য একটি কমান্ড চালানো)? বা আপনার পরে ব্যবহারের জন্য শব্দের একটি তালিকা সঞ্চয় করতে হবে?
ডিভিকে

উত্তর:


281

আপনি কি স্ট্রিং ভেরিয়েবলটিকে একটি forলুপে পাস করার চেষ্টা করেছেন ? এক জন্য বাশ, স্বয়ংক্রিয়ভাবে সাদা স্পেসে বিভক্ত হবে।

sentence="This is   a sentence."
for word in $sentence
do
    echo $word
done

 

This
is
a
sentence.

1
@ মোব্রুল - এর একমাত্র অপূর্ণতা হ'ল আপনি আরও সহজে প্রক্রিয়াজাতকরণের জন্য আউটপুট সহজেই ক্যাপচার করতে পারবেন না (কমপক্ষে কোনও উপায় আমি মনে করি না)।
STDOUT এ

4
আপনি শুধু একটি পরিবর্তনশীল তা যোগ পারে: A=${A}${word})
লুকাস জোনস

1
$ পাঠ্য সেট করুন [এটি শব্দগুলিকে $ 1, $ 2, $ 3 ... ইত্যাদির মধ্যে রাখবে]
রাজেশ

32
আসলে এই কৌশলটি কেবল একটি ভুল সমাধান নয়, এটি শেল গ্লোব্বিংয়ের কারণেও অত্যন্ত বিপজ্জনক । প্রত্যাশিত পরিবর্তে touch NOPE; var='* a *'; for a in $var; do echo "[$a]"; doneআউটপুট (পাঠযোগ্যতার জন্য এসপিসি দ্বারা প্রতিস্থাপিত এলএফ)। [NOPE] [a] [NOPE][*] [a] [*]
টিনো

@ মোব আমি কিছু নির্দিষ্ট স্ট্রিংয়ের উপর ভিত্তি করে স্ট্রিংটি বিভক্ত করতে চাইলে আমার কী করা উচিত? উদাহরণস্বরূপ ".xlsx" বিভাজক।

295

আমি পৃথক উপাদান অ্যাক্সেস করতে সক্ষম হতে একটি অ্যারেতে রূপান্তর পছন্দ করি:

sentence="this is a story"
stringarray=($sentence)

এখন আপনি সরাসরি পৃথক উপাদান অ্যাক্সেস করতে পারেন (এটি 0 দিয়ে শুরু হয়):

echo ${stringarray[0]}

অথবা লুপের জন্য স্ট্রিংয়ে ফিরে রূপান্তর করুন:

for i in "${stringarray[@]}"
do
  :
  # do whatever on $i
done

অবশ্যই স্ট্রিংটির মাধ্যমে সরাসরি লুপিংয়ের আগে উত্তর দেওয়া হয়েছিল, তবে সেই উত্তরটির পরে ব্যবহারের জন্য পৃথক উপাদানগুলির উপর নজর রাখার অসুবিধা ছিল:

for i in $sentence
do
  :
  # do whatever on $i
done

আরও দেখুন ব্যাশ এরে রেফারেন্স


26
দুঃখজনকভাবে পুরোপুরি নিখুঁত নয়, কারণ শেল-globbing এর: touch NOPE; var='* a *'; arr=($var); set | grep ^arr=আউটপুট arr=([0]="NOPE" [1]="a" [2]="NOPE")প্রত্যাশিত পরিবর্তেarr=([0]="*" [1]="a" [2]="*")
টিনো

@ টিনো: আপনি যদি গ্লোববিংকে হস্তক্ষেপ করতে না চান তবে কেবল এটিকে বন্ধ করুন। সমাধানটি তখন ওয়াইল্ডকার্ডগুলির সাথেও দুর্দান্ত কাজ করবে। এটি আমার মতে সেরা পন্থা।
আলেকজান্দ্রোস

3
@ অ্যালেক্সানড্রোস আমার দৃষ্টিভঙ্গি কেবলমাত্র নিদর্শনগুলি ব্যবহার করা, যা ডিফল্টরূপে সুরক্ষিত এবং প্রতিটি প্রসঙ্গে নিখুঁতভাবে কাজ করে। সুরক্ষিত সমাধান পেতে শেল-গ্লোববিং পরিবর্তন করার প্রয়োজনীয়তা কেবল একটি খুব বিপজ্জনক পথের চেয়ে বেশি, এটি ইতিমধ্যে অন্ধকার। সুতরাং আমার পরামর্শটি হ'ল এখানে কখনও এ জাতীয় প্যাটার্ন ব্যবহার করতে অভ্যস্ত হবেন না কারণ শীঘ্রই বা পরে আপনি কিছু বিশদ সম্পর্কে ভুলে যাবেন এবং তারপরে কেউ আপনার বাগটি ব্যবহার করে। আপনি প্রেসে এই জাতীয় শোষণের প্রমাণ পেতে পারেন। প্রতি. একক। দিন.
টিনো

86

কেবল শেল্টগুলি "সেট" বিল্ট-ইন ব্যবহার করুন। উদাহরণ স্বরূপ,

সেট $ পাঠ্য

এরপরে, $ পাঠ্যের পৃথক শব্দগুলি $ 1, $ 2, $ 3 ইত্যাদিতে হবে দৃ rob়তার জন্য, সাধারণত একটি হয়

সেট - জাঙ্ক $ পাঠ্য
পরিবর্তন

কেসটি হ্যান্ডেল করতে যেখানে $ পাঠ্য খালি রয়েছে বা কোনও ড্যাশ দিয়ে শুরু করুন। উদাহরণ স্বরূপ:

পাঠ্য = "এটি একটি পরীক্ষা"
সেট - জাঙ্ক $ পাঠ্য
পরিবর্তন
শব্দের জন্য; করা
  প্রতিধ্বনি "[$ শব্দ]"
সম্পন্ন

এই মুদ্রণ

[এই]
[হয়]
[এক]
[TEST]

5
এটি পৃথক অংশগুলি সরাসরি অ্যাক্সেস করতে পারে যাতে ভেরটি বিভক্ত করার একটি দুর্দান্ত উপায়। +1 টি; আমার সমস্যা সমাধান করুন
চেকিসফট

আমি ব্যবহার করার পরামর্শ দিচ্ছিলাম awkতবে setএটি আরও সহজ। আমি এখন setফ্যানবয়। ধন্যবাদ @ ইডেলিক!
ইজমির রামিরেজ

22
আপনি যদি এই জাতীয় জিনিসগুলি করেন তবে শেল গ্লোব্বিং সম্পর্কে সচেতন হন: প্রত্যাশার পরিবর্তে touch NOPE; var='* a *'; set -- $var; for a; do echo "[$a]"; doneআউটপুট । কেবলমাত্র এটি ব্যবহার করুন যদি আপনি 101% নিশ্চিত হন যে বিভক্ত স্ট্রিংয়ে কোনও শেল মেটাচ্যাকার্টার নেই! [NOPE] [a] [NOPE][*] [a] [*]
টিনো

4
@ টিনো: এই সমস্যাটি কেবল এখানেই নয়, সর্বত্র প্রযোজ্য তবে এই ক্ষেত্রে আপনি গ্লোব্বিং নিষ্ক্রিয় করার ঠিক set -fআগে set -- $varএবং set +fপরে করতে পারেন could
ইডেলিক

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

81

BASH 3 এবং উপরের সম্ভবত সবচেয়ে সহজ এবং সর্বাধিক সুরক্ষিত উপায় হ'ল:

var="string    to  split"
read -ra arr <<<"$var"

( arrঅ্যারেটি যেখানে স্ট্রিংয়ের বিভক্ত অংশগুলি নিয়ে যায়) বা, যদি ইনপুটটিতে নতুন লাইন থাকতে পারে এবং আপনি কেবল প্রথম লাইনের চেয়ে আরও কিছু চান:

var="string    to  split"
read -ra arr -d '' <<<"$var"

(দয়া করে স্থানটি নোট করুন -d '', এটি ছেড়ে দেওয়া যাবে না) তবে এটি আপনাকে একটি অপ্রত্যাশিত নতুন লাইন দিতে পারে <<<"$var"(যেহেতু এটি শেষ পর্যন্ত একটি এলএফ যোগ করে))

উদাহরণ:

touch NOPE
var="* a  *"
read -ra arr <<<"$var"
for a in "${arr[@]}"; do echo "[$a]"; done

প্রত্যাশিত ফলাফল

[*]
[a]
[*]

যেহেতু এই সমাধানটি (এখানে পূর্ববর্তী সমস্ত সমাধানগুলির বিপরীতে) অপ্রত্যাশিত এবং প্রায়শই নিয়ন্ত্রণহীন শেল গ্লোববিংয়ের ঝুঁকিতে নেই।

এছাড়াও এটি আপনাকে সম্ভবত চাইলে আইএফএসের সম্পূর্ণ ক্ষমতা দেয়:

উদাহরণ:

IFS=: read -ra arr < <(grep "^$USER:" /etc/passwd)
for a in "${arr[@]}"; do echo "[$a]"; done

ফলাফল যেমন:

[tino]
[x]
[1000]
[1000]
[Valentin Hilbig]
[/home/tino]
[/bin/bash]

আপনি দেখতে পাচ্ছেন, স্পেসগুলিও এইভাবে সংরক্ষণ করা যায়:

IFS=: read -ra arr <<<' split  :   this    '
for a in "${arr[@]}"; do echo "[$a]"; done

আউটপুট

[ split  ]
[   this    ]

দয়া করে নোট করুন যে IFSBASH এ পরিচালনা করা নিজস্ব নিজস্ব একটি বিষয়, সুতরাং আপনার পরীক্ষাগুলি করুন, এটিতে কিছু আকর্ষণীয় বিষয়:

  • unset IFS: এসপিসি, ট্যাব, এনএল এবং লাইনের শুরু এবং শেষের রানগুলি উপেক্ষা করে
  • IFS='': কোনও ক্ষেত্র বিভাজন নয়, কেবল সবকিছু পড়ে
  • IFS=' ': এসপিসির চালনা (এবং কেবল এসপিসি)

কিছু শেষ উদাহরণ

var=$'\n\nthis is\n\n\na test\n\n'
IFS=$'\n' read -ra arr -d '' <<<"$var"
i=0; for a in "${arr[@]}"; do let i++; echo "$i [$a]"; done

আউটপুট

1 [this is]
2 [a test]

যখন

unset IFS
var=$'\n\nthis is\n\n\na test\n\n'
read -ra arr -d '' <<<"$var"
i=0; for a in "${arr[@]}"; do let i++; echo "$i [$a]"; done

আউটপুট

1 [this]
2 [is]
3 [a]
4 [test]

BTW:

  • আপনি যদি $'ANSI-ESCAPED-STRING'এটিতে অভ্যস্ত না হন তবে এটি টাইমসভার।

  • আপনি যদি -r( অন্তর্ভুক্ত read -a arr <<<"$var") অন্তর্ভুক্ত না করেন তবে পড়ুন ব্যাকস্ল্যাশ পালাতে পারে। এটি পাঠকের জন্য অনুশীলন হিসাবে রেখে দেওয়া হয়েছে।


দ্বিতীয় প্রশ্নের জন্য:

স্ট্রিংয়ের জন্য কিছু পরীক্ষা করার জন্য আমি সাধারণত caseদৃ to়ভাবে আটকে থাকি কারণ এটি একসাথে একাধিক কেস পরীক্ষা করতে পারে (দ্রষ্টব্য: কেসটি কেবল প্রথম ম্যাচটি সম্পাদন করে, যদি আপনার পতনের জন্য মাল্টিপ্লেস caseস্টেটমেন্ট প্রয়োজন হয়), এবং এই প্রয়োজনটি প্রায়শই ক্ষেত্রে হয় (শ্লেষ) অভিপ্রেত):

case "$var" in
'')                empty_var;;                # variable is empty
*' '*)             have_space "$var";;        # have SPC
*[[:space:]]*)     have_whitespace "$var";;   # have whitespaces like TAB
*[^-+.,A-Za-z0-9]*) have_nonalnum "$var";;    # non-alphanum-chars found
*[-+.,]*)          have_punctuation "$var";;  # some punctuation chars found
*)                 default_case "$var";;      # if all above does not match
esac

সুতরাং আপনি এসপিসির জন্য এটি পরীক্ষা করে ফেরতের মানটি সেট করতে পারেন:

case "$var" in (*' '*) true;; (*) false;; esac

কেন case? কারণ এটি সাধারণত রেজেক্স সিকোয়েন্সগুলির চেয়ে কিছুটা বেশি পঠনযোগ্য এবং শেল মেটাচার্যাক্টরের জন্য এটি 99% সমস্ত প্রয়োজন খুব ভালভাবে পরিচালনা করে।


2
বিশ্বব্যাপী বিষয়গুলি হাইলাইট করা এবং এর ব্যাপকতার কারণে এই উত্তরটি আরও বেশি অগ্রাধিকারের দাবি রাখে
ব্রায়ান

@ ব্রায়ান ধন্যবাদ দয়া করে নোট করুন যে আপনি ব্যবহার করতে set -fবা set -o noglobগ্লোব্বিংয়ের স্যুইচ করতে পারেন , যেমন শেল মেটাচ্যাকাররা আর এই প্রসঙ্গে ক্ষতি করতে পারে না। তবে আমি সত্যিই এর বন্ধু নই, কারণ এটি শেলের অনেক বেশি শক্তি পিছনে ফেলেছে / এই সেটিংটি পিছনে পিছনে স্যুইচ করার প্রবণতা খুব ত্রুটিযুক্ত।
টিনো

2
বিস্ময়কর উত্তর, প্রকৃতপক্ষে আরও upvotes প্রাপ্য। কেস এর পতনের দিকে দিক নোট - আপনি এটি ;&অর্জন করতে পারেন । বাশের কোন সংস্করণে উপস্থিত হয়েছিল তা পুরোপুরি নিশ্চিত নয়। আমি একজন ৪.৩ ব্যবহারকারী
সের্গি কলডিয়াজন্য

2
@ সার্জকে লক্ষ্য করার জন্য ধন্যবাদ, কারণ আমি এটি এখনও জানতাম না! সুতরাং আমি এটি সন্ধান করেছি, এটি বাশ 4-এ হাজির । ;&সি মত প্যাটার্ন চেক ছাড়া fallthrough বাধ্য সেই সময় হয় ;;&যা শুধু আরও প্যাটার্ন চেক করতে চলতে থাকে। তাই ;;ভালো হয় if ..; then ..; else if ..এবং ;;&ভালো হয় if ..; then ..; fi; if .., যেখানে ;&মত হয় m=false; if ..; then ..; m=:; fi; if $m || ..; then ..); - একটি (অন্যদের থেকে) শেখার স্টপ কখনও
টিনো

@ টিনো এটি একেবারেই সত্য - শেখা একটি ধারাবাহিক প্রক্রিয়া। প্রকৃতপক্ষে, ;;&আপনি মন্তব্য করার আগে আমি জানতাম না : ডি ধন্যবাদ, এবং শেলটি আপনার সাথে থাকতে পারে;)
সের্গি কলডিয়াজহনি

43
$ echo "This is   a sentence." | tr -s " " "\012"
This
is
a
sentence.

স্পেসগুলি পরীক্ষা করার জন্য, গ্রেপ ব্যবহার করুন:

$ echo "This is   a sentence." | grep " " > /dev/null
$ echo $?
0
$ echo "Thisisasentence." | grep " " > /dev/null     
$ echo $?
1

1
ইন BASH echo "X" |সাধারণত দ্বারা প্রতিস্থাপিত হতে পারে <<<"X", এরকম: grep -s " " <<<"This contains SPC"। আপনি যদি echo X | read varএর বিপরীতে কিছু করেন তবে আপনি পার্থক্যটি চিহ্নিত করতে পারেন read var <<< X। কেবলমাত্র পরেরটি varবর্তমান শেলটিতে পরিবর্তনশীল আমদানি করে, প্রথম ভেরিয়েন্টে অ্যাক্সেস করার জন্য আপনাকে অবশ্যই এই জাতীয় দলবদ্ধ করতে হবে:echo X | { read var; handle "$var"; }
টিনো

17

(ক) একটি বাক্যকে তার কথায় বিভক্ত করতে (স্থান পৃথক করে) আপনি কেবল ডিফল্ট আইএফএস ব্যবহার করে ব্যবহার করতে পারেন

array=( $string )


নিম্নলিখিত স্নিপেট চলমান উদাহরণ

#!/bin/bash

sentence="this is the \"sentence\"   'you' want to split"
words=( $sentence )

len="${#words[@]}"
echo "words counted: $len"

printf "%s\n" "${words[@]}" ## print array

আউটপুট হবে

words counted: 8
this
is
the
"sentence"
'you'
want
to
split

আপনি দেখতে পাচ্ছেন যে কোনও সমস্যা ছাড়াই আপনি একক বা ডাবল উদ্ধৃতিও ব্যবহার করতে পারেন

দ্রষ্টব্য:
- এটি মূলত ভিড়ের জবাব একই , তবে এইভাবে আপনি আর কোনও প্রয়োজনের জন্য অ্যারেটি সঞ্চয় করেন store আপনার যদি কেবল একটি একক লুপের প্রয়োজন হয় তবে আপনি তার উত্তরটি ব্যবহার করতে পারেন যা এক লাইন খাটো :)
- ডিলিমিটারের ভিত্তিতে স্ট্রিংকে বিভক্ত করতে বিকল্প পদ্ধতির জন্য দয়া করে এই প্রশ্নটি দেখুন


(খ) স্ট্রিংয়ের কোনও অক্ষরের জন্য যাচাই করতে আপনি নিয়মিত প্রকাশের ম্যাচও ব্যবহার করতে পারেন।
যে স্থানের অক্ষর আপনি ব্যবহার করতে পারেন তার উপস্থিতি যাচাই করার উদাহরণ:

regex='\s{1,}'
if [[ "$sentence" =~ $regex ]]
    then
        echo "Space here!";
fi

রেজেক্স ইঙ্গিতের জন্য (বি) a +1, তবে -1 ভুল সমাধানের জন্য (এ) কারণ এটি শেল গ্লোব্বিংয়ের প্রবণতা। ;)
টিনো


1
echo $WORDS | xargs -n1 echo

এটি প্রতিটি শব্দের আউটপুট দেয়, এরপরে আপনি যথাযথ দেখতে দেখতে আপনি সেই তালিকাটি প্রক্রিয়া করতে পারেন।

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