इसका सरल उत्तर है: सभी सीमांकक को एक (पहले) को ध्वस्त करें।
इसके लिए लूप की आवश्यकता होती है (जो log(N)
समय से कम चलता है ):
var=':a bc::d ef:#$%_+$$% ^%&*(*&*^
$#,.::ghi::*::' # a long test string.
d=':@!#$%^&*()_+,.' # delimiter set
f=${d:0:1} # first delimiter
v=${var//["$d"]/"$f"}; # convert all delimiters to
: # the first of the delimiter set.
tmp=$v # temporal variable (v).
while
tmp=${tmp//["$f"]["$f"]/"$f"}; # collapse each two delimiters to one
[[ "$tmp" != "$v" ]]; # If there was a change
do
v=$tmp; # actualize the value of the string.
done
यह सब करने के लिए छोड़ दिया है सही ढंग से एक सीमांकक पर स्ट्रिंग को विभाजित करने के लिए , और इसे प्रिंट करें:
readarray -td "$f" arr < <(printf '%s%s' "$v"'' "$f")
printf '<%s>' "${arr[@]}" ; echo
set -f
आईएफएस को बदलने के लिए न तो जरूरत है और न ही।
रिक्त स्थान, newlines और ग्लोब पात्रों के साथ परीक्षण किया गया। सारा काम। काफी धीमा (एक शेल लूप होने की उम्मीद की जानी चाहिए)।
लेकिन केवल बैश के लिए (बैश 4.4+ विकल्प के कारण-d
रीडअरे के कारण)।
श
एक शेल संस्करण एक सरणी का उपयोग नहीं कर सकता है, केवल उपलब्ध सरणी स्थितीय पैरामीटर हैं।
उपयोग करना tr -s
केवल एक पंक्ति है (IFS स्क्रिप्ट में नहीं बदलता है):
set -f; IFS=$f command eval set -- '$(echo "$var" | tr -s "$d" "[$f*]" )""'
और इसे प्रिंट करें:
printf '<%s>' "$@" ; echo
अभी भी धीमा है, लेकिन ज्यादा नहीं।
command
बॉर्न में कमांड अमान्य है।
Zsh में, command
केवल बाहरी आदेशों को कॉल करता है और यदि command
उपयोग किया जाता है तो निष्फल विफल हो जाता है।
Ksh में, यहां तक कि command
, IFS के मूल्य को वैश्विक दायरे में बदल दिया जाता है।
और command
mksh से संबंधित गोले (mksh, lksh, पॉश) में विभाजन को विफल command
बनाता है कमांड को हटाने से कोड अधिक गोले पर चलता है। लेकिन: हटाने command
से IFS अधिकांश गोले में अपना मूल्य बनाए रखेगा (eval एक विशेष बिलिन है) को छोड़कर बश में (पॉज़िक्स मोड के बिना) और डिफॉल्ट (नो इम्यूलेशन) मोड में zsh। इस अवधारणा को डिफ़ॉल्ट zsh में या तो साथ या बिना काम करने के लिए नहीं बनाया जा सकता है command
।
एकाधिक वर्ण IFS
हां, IFS बहु चरित्र वाला हो सकता है, लेकिन प्रत्येक वर्ण एक तर्क उत्पन्न करेगा:
set -f; IFS="$d" command eval set -- '$(echo "$var" )""'
printf '<%s>' "$@" ; echo
उत्पादन होगा:
<><a bc><><d ef><><><><><><><><>< ><><><><><><><><><
><><><><><><ghi><><><><><>
बैश के साथ, आप command
श / POSIX अनुकरण में नहीं होने पर शब्द को छोड़ सकते हैं । आदेश ksh93 में विफल हो जाएगा (IFS परिवर्तित मूल्य रखता है)। Zsh में कमांड command
zsh को खोजने की कोशिश करता हैeval
बाहरी कमांड के रूप में करता है (जो इसे नहीं ) और विफल हो जाता है।
क्या होता है कि केवल एक IFS वर्ण जो एक सीमांकक के लिए स्वतः ढह गए हैं IFS सफेद स्थान हैं।
IFS में एक स्थान एक के बाद एक लगातार सभी स्थानों को ध्वस्त कर देगा। एक टैब सभी टैब को ध्वस्त कर देगा। एक स्थान और एक टैब एक सीमांकक के लिए रिक्त स्थान और / या टैब को चलाता है। नईलाइन के साथ विचार को दोहराएं।
कई सीमांकक को ढहाने के लिए आसपास कुछ करतब दिखाने की आवश्यकता होती है।
इनपुट में ASCII 3 (0x03) का उपयोग नहीं किया गया है var
:
var=${var// /$'\3'} # protect spaces
var=${var//["$d"]/ } # convert all delimiters to spaces
set -f; # avoid expanding globs.
IFS=" " command eval set -- '""$var""' # split on spaces.
set -- "${@//$'\3'/ }" # convert spaces back.
Ksh, zsh और bash के बारे में अधिकांश टिप्पणियां (के बारे में) command
और IFS) के अभी भी यहां लागू होती हैं।
$'\0'
पाठ इनपुट में मान कम संभावित होगा, लेकिन बैश चर में NULs ( 0x00
) नहीं हो सकता है ।
समान स्ट्रिंग ऑपरेशन करने के लिए श में कोई आंतरिक कमांड नहीं हैं, इसलिए sh स्क्रिप्ट के लिए एकमात्र समाधान है।