শেলটিতে জাভাস্ক্রিপ্টের "স্প্লিট ()" এর মতো কিছু আছে কি?


18

split()একটি অ্যারেতে স্ট্রিং ভাঙ্গতে জাভাস্ক্রিপ্টে এটি ব্যবহার করা খুব সহজ ।

শেল লিপি সম্পর্কে কি?

বলুন আমি এটি করতে চাই:

$ script.sh var1_var2_var3

যখন ব্যবহারকারী var1_var2_var3স্ক্রিপ্ট.শকে এরকম স্ট্রিং দেয়, স্ক্রিপ্টের অভ্যন্তরে এটি স্ট্রিংটিকে একটি অ্যারেতে রূপান্তরিত করে

array=( var1 var2 var3 )
for name in ${array[@]}; do
    # some code
done

1
আপনি কী shellব্যবহার করছেন, আপনার সাথে যা bashকরতে পারেIFS='_' read -a array <<< "${string}"
gwillie

perlএটাও করতে পারে এটি "খাঁটি" শেল নয়, তবে এটি বেশ সাধারণ।
সোবারিক

@ সোব্রিক আমি "খাঁটি" শেলের প্রযুক্তিগত সংজ্ঞা সম্পর্কেও অবগত নই, তবে নোড.জেএস রয়েছে।
এমুরি

আমি সম্ভবত এটি 'ডিফল্টরূপে আমার লিনাক্স বাক্সে ইনস্টল করা' নিয়ে কাজ করার ঝোঁক রাখি এবং
মিনটিয়াকে হ্রাস

উত্তর:


24

বোর্ন / পসিক্স-এর মতো শেলগুলির একটি স্প্লিট + গ্লোব অপারেটর রয়েছে এবং প্রতিবার আপনি প্যারামিটার এক্সপেনশন ( $var, $-...), কমান্ড সাবস্টিটিউশন ( $(...)), বা পাটিগণিতের সম্প্রসারণ ( $((...))) তালিকার প্রসঙ্গে ছাড়াই রেখে যাবেন।

প্রকৃতপক্ষে, আপনি for name in ${array[@]}পরিবর্তে এটি করার সময় আপনি ভুলক্রমে এটি শুরু করেছিলেন for name in "${array[@]}"। (আসলে, আপনার সচেতন হওয়া উচিত যে ভুলরূপে অপারেটরকে অনুরোধ করা অনেকগুলি বাগ এবং সুরক্ষার দুর্বলতার উত্স )।

যে অপারেটর এর মাধ্যমে কনফিগার করা $IFSবিশেষ প্যারামিটার এবং (কি অক্ষর বিভক্ত (যদিও যে স্থান, ট্যাব হুঁশিয়ার এবং একটি বিশেষ চিকিত্সা আছে) গ্রহণ সম্পর্কে newline বলুন পর্যন্ত) -fনিষ্ক্রিয় করতে বিকল্প ( set -f) অথবা সক্রিয় করুন ( set +f) globঅংশ।

এছাড়াও মনে রাখবেন যখন Sমধ্যে $IFSমূলত ছিল (বোর্ন শেল যেখানে $IFSথেকে আসে) SPOSIX শাঁস এ, eparator, অক্ষর $IFSবরং হিসেবে দেখা উচিত বিভেদক বা terminators (উদাহরণের জন্য নীচে দেখুন)।

সুতরাং বিভক্ত করতে _:

string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
array=($string) # invoke the split+glob operator

for i in "${array[@]}"; do # loop over the array elements.

বিভাজক এবং ডিলিমিটারের মধ্যে পার্থক্য দেখতে , চেষ্টা করুন:

string='var1_var2_'

এটি এটিকে কেবল var1এবং var2কেবল (অতিরিক্ত খালি উপাদান ছাড়াই) বিভক্ত করবে ।

সুতরাং, এটি জাভাস্ক্রিপ্ট এর অনুরূপ করতে split()আপনার একটি অতিরিক্ত পদক্ষেপ প্রয়োজন:

string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
temp=${string}_ # add an extra delimiter
array=($temp) # invoke the split+glob operator

(নোট এটি একটি খালি বিভক্ত হবে $stringমধ্যে 1 (না 0 ) উপাদান, জাভাস্ক্রিপ্ট মত split())।

বিশেষ চিকিত্সা ট্যাবটি দেখতে, স্থান এবং নিউলাইনটি গ্রহণ করুন, তুলনা করুন:

IFS=' '; string=' var1  var2  '

(যেখানে আপনি পাবেন var1এবং var2) সাথে

IFS='_'; string='_var1__var2__'

যেখানে আপনি পাবেন: '', var1, '', var2, ''

মনে রাখবেন যে zshশেলটি স্প্লিট + গ্লোব অপারেটরটিকে স্পষ্টভাবে অনুরোধ করে না যতক্ষণ না ইনসুলেশন shবা kshঅনুকরণ হয়। সেখানে, আপনি এটি স্পষ্টভাবে প্রার্থনা করতে হবে। $=stringবিভক্ত অংশের $~stringজন্য, গ্লোব অংশের $=~stringজন্য ( উভয়ের জন্য), এবং এর একটি বিভাজন অপারেটরও রয়েছে যেখানে আপনি পৃথককে নির্দিষ্ট করতে পারেন:

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

বা খালি উপাদান সংরক্ষণ করতে:

array=("${(@s:_:)string}")

মনে রাখবেন যে বিভাজনেরs জন্য রয়েছে , সীমানা ছাড়াই নয় (এর সাথে একটি পরিচিত পসিক্স অ-কনফরমেশনও নেই )। এটি জাভাস্ক্রিপ্টের থেকে পৃথক যে একটি খালি স্ট্রিং 0 (1 না) উপাদানকে বিভক্ত করা হয়েছে।$IFSzshsplit()

$IFS-স্প্লিটিংয়ের সাথে একটি উল্লেখযোগ্য পার্থক্য হ'ল স্ট্রিংয়ের ${(s:abc:)string}উপর বিভক্ত হওয়া abc, যখন এর সাথে IFS=abcবিভক্ত হবে a, bবা c

সঙ্গে zshএবং ksh93, বিশেষ চিকিত্সা স্থান, ট্যাব বা সম্পর্কে newline পাওয়া তাদের মধ্যে দ্বিগুন দ্বারা মুছে ফেলা হতে পারে $IFS

Historicতিহাসিক নোট হিসাবে, বোর্ন শেল (পূর্বপুরুষ বা আধুনিক পসিক্স শেলস) সর্বদা শূন্য উপাদানগুলিকে ছিনিয়ে নিয়েছিল। এর অ-ডিফল্ট মানগুলির সাথে split @ বিভক্তকরণ এবং প্রসারণ সম্পর্কিত অনেকগুলি বাগ রয়েছে $IFS। উদাহরণস্বরূপ IFS=_; set -f; set -- $@সমতুল্য হবে না IFS=_; set -f; set -- $1 $2 $3...

রেগেক্সপসে বিভক্ত

এখন জাভাস্ক্রিপ্টের কাছাকাছি এমন কিছু split()যা নিয়মিত অভিব্যক্তিতে বিভক্ত হতে পারে, আপনাকে বাহ্যিক উপযোগগুলির উপর নির্ভর করতে হবে।

পসিক্স সরঞ্জাম-বুকে awkএকটি splitঅপারেটর রয়েছে যা প্রসারিত নিয়মিত অভিব্যক্তিগুলিতে বিভক্ত হয়ে যায় (এগুলি জাভাস্ক্রিপ্ট দ্বারা সমর্থিত পার্ল-এর মতো নিয়মিত এক্সপ্রেশনগুলির কম-বেশি হয়)।

split() {
  awk -v q="'" '
    function quote(s) {
      gsub(q, q "\\" q q, s)
      return q s q
    }
    BEGIN {
      n = split(ARGV[1], a, ARGV[2])
      for (i = 1; i <= n; i++) printf " %s", quote(a[i])
      exit
    }' "$@"
}
string=a__b_+c
eval "array=($(split "$string" '[_+]+'))"

zshশেল পার্ল সামঞ্জস্যপূর্ণ রেগুলার এক্সপ্রেশনের (তার জন্য সমর্থন builtin হয়েছে zsh/pcre, মডিউল), কিন্তু এটি ব্যবহার একটি স্ট্রিং বিভক্ত করা সম্ভব যদিও তুলনামূলকভাবে কষ্টকর হয়।


ট্যাব, স্পেস এবং নিউলাইন দিয়ে বিশেষ চিকিত্সার কোনও কারণ আছে?
cuonglm

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

ঠিক আছে, সাম্প্রতিক যুক্ত বোর্ন শেল নোটটি আমাকে অবাক করেছে। এবং সম্পূর্ণ করার জন্য, আপনার zshস্ট্রিং দিয়ে চিকিত্সার জন্য নোটটি যুক্ত করতে হবে যাতে এতে 2 বা আরও বেশি অক্ষর থাকে ${(s:string:)var}? যদি যোগ করা হয়, আমি আমার উত্তরটি মুছতে পারি :)
cuonglm

1
"আপনি আরও মনে রাখবেন যে $ আইএফএসে এস বিভাজনকারী নয়, ডিলিমিটারের জন্য?" আমি বলবিজ্ঞান বুঝতে এবং বিভাজক কিন্তু trailing এটি উপেক্ষা করে Sদাঁড়াতেন পৃথককারী না বিভেদক । কমপক্ষে, আমার বাশের ম্যানুয়ালটি এটাই বলে।
টেরডন

@ ইটারডন, $IFSবোর্ন শেল থেকে এসেছে যেখানে এটি বিভাজক ছিল , কেএস নাম পরিবর্তন না করে আচরণ পরিবর্তন করেছিল। আমি উল্লেখ করেছি যে চাপ দেওয়ার জন্য split+glob(zsh বা pdksh ব্যতীত) কেবল আর বিভাজন হয় না।
স্টাফেন চেজেলাস

7

হ্যাঁ, এটি ব্যবহার করুন IFSএবং সেট করুন _। তারপরে read -aএকটি অ্যারেতে সঞ্চয় করতে ব্যবহার করুন ( -rব্যাকস্ল্যাশ সম্প্রসারণ বন্ধ করা হয়)। নোট করুন যে এটি ব্যাশের সাথে নির্দিষ্ট; কিছুটা আলাদা সিনট্যাক্স সহ ksh এবং zsh এর অনুরূপ বৈশিষ্ট্য রয়েছে এবং প্লেইন sh এর অ্যারে ভেরিয়েবলগুলি মোটেই নেই।

$ r="var1_var2_var3"
$ IFS='_' read -r -a array <<< "$r"
$ for name in "${array[@]}"; do echo "+ $name"; done
+ var1
+ var2
+ var3

থেকে man bash:

পড়া

-এ aname

শব্দগুলি অ্যারে ভেরিয়েবল আনামের ক্রমিক সূচকগুলিতে বরাদ্দ করা হয়, 0 থেকে শুরু করে কোনও নতুন মান নির্ধারিত হওয়ার আগে aname আনসেট করা হয়। অন্যান্য নামের যুক্তি উপেক্ষা করা হয়।

IFS

অভ্যন্তরীণ ক্ষেত্র বিভাজক যা প্রসারণের পরে শব্দ বিভাজনের জন্য এবং পঠিত বিল্টিন কমান্ডের সাহায্যে শব্দের মধ্যে লাইনগুলি বিভক্ত করতে ব্যবহৃত হয়। ডিফল্ট মান `` ''।

নোট করুন যে readপ্রথম নতুন লাইনে থামে। পাশ -d ''থেকে readএড়াতে, কিন্তু সেই ক্ষেত্রে, সেখানে কারণে শেষে একটি অতিরিক্ত সম্পর্কে newline হতে হবে <<<অপারেটর। আপনি এটি ম্যানুয়ালি অপসারণ করতে পারেন:

IFS='_' read -r -d '' -a array <<< "$r"
array[$((${#array[@]}-1))]=${array[$((${#array[@]}-1))]%?}

ধরে নেওয়া $rহয় যে নতুন লাইন অক্ষর বা ব্যাকস্ল্যাশ নেই। এছাড়াও মনে রাখবেন যে এটি কেবল bashশেলের সাম্প্রতিক সংস্করণগুলিতে কাজ করবে ।
স্টাফেন চেজেলাস

@ স্টাফেনচাজেলাস ভাল পয়েন্ট। হ্যাঁ, এটি একটি স্ট্রিংয়ের "বেসিক" কেস। বাকিদের জন্য, প্রত্যেককে আপনার বিস্তৃত উত্তরের জন্য যাওয়া উচিত। এর সংস্করণগুলি সম্পর্কে bash, read -aবাশ 4 এ প্রবর্তিত হয়েছিল, তাই না?
ফেডরকিই

1
দুঃখিত আমার খারাপ, আমি ভেবেছিলাম <<<সম্প্রতি এটি যুক্ত হয়েছিল bashতবে মনে হয় এটি 2.05b (2002) থেকে রয়েছে been read -aতার চেয়েও পুরনো। (এবং মিক্স এবং ইয়াশ) <<<থেকেও আসে zshএবং সমর্থিত ksh93তবে read -aবাশ-নির্দিষ্ট (এটি -Aksh93, যশ এবং জেডএসে)।
স্টাফেন চেজেলাস

@ স্টাফেনচেজেলাসের এই পরিবর্তনগুলি কখন ঘটেছিল তা খুঁজে পাওয়ার কোনও "সহজ" উপায় আছে? আমি বলি "সহজ" রিলিজ ফাইলগুলি খনন না করা, সম্ভবত কোনও পৃষ্ঠা তাদের সমস্ত দেখায়।
ফেডরকিই

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