क्या पाइपिंग, स्थानांतरण, या पैरामीटर विस्तार अधिक कुशल है?


26

मैं कुछ मानों के माध्यम से पुनरावृति करने का सबसे कुशल तरीका खोजने की कोशिश कर रहा हूं जो शब्दों की एक अंतरिक्ष से अलग सूची में एक दूसरे से दूर मूल्यों की एक सुसंगत संख्या है (मैं एक सरणी का उपयोग नहीं करना चाहता)। उदाहरण के लिए,

list="1 ant bat 5 cat dingo 6 emu fish 9 gecko hare 15 i j"

इसलिए मैं सूची के माध्यम से केवल पुनरावृति करने में सक्षम होना चाहता हूं और केवल 1,5,6,9 और 15 का उपयोग करना चाहता हूं।

संपादित करें: मुझे यह स्पष्ट करना चाहिए था कि मैं जिन मूल्यों को सूची से प्राप्त करने की कोशिश कर रहा हूं, उन्हें बाकी सूची से प्रारूप में भिन्न नहीं होना चाहिए। जो उन्हें विशेष बनाता है वह सूची में उनकी स्थिति पूरी तरह से है (इस मामले में, स्थिति 1,4,7 ...)। तो सूची हो सकती है,1 2 3 5 9 8 6 90 84 9 3 2 15 75 55लेकिन मैं अभी भी वही संख्या चाहता हूं। और यह भी, मैं यह मानकर चलना चाहता हूं कि मुझे सूची की लंबाई का पता नहीं है।

मैंने अब तक जिन तरीकों के बारे में सोचा है वे हैं:

विधि 1

set $list
found=false
find=9
count=1
while [ $count -lt $# ]; do
    if [ "${@:count:1}" -eq $find ]; then
    found=true
    break
    fi
    count=`expr $count + 3`
done

विधि 2

set list
found=false
find=9
while [ $# ne 0 ]; do
    if [ $1 -eq $find ]; then
    found=true
    break
    fi
    shift 3
done

विधि 3 मुझे पूरा यकीन है कि पाइपिंग इसे सबसे खराब विकल्प बनाती है, लेकिन मैं एक ऐसी विधि खोजने की कोशिश कर रहा था जो सेट का उपयोग न करे, जिज्ञासा से बाहर।

found=false
find=9
count=1
num=`echo $list | cut -d ' ' -f$count`
while [ -n "$num" ]; do
    if [ $num -eq $find ]; then
    found=true
    break
    fi
    count=`expr $count + 3`
    num=`echo $list | cut -d ' ' -f$count`
done

तो क्या सबसे कुशल होगा, या मैं एक सरल विधि याद आ रही है?


10
मैं पहली बार एक शेल स्क्रिप्ट का उपयोग नहीं करूंगा यदि दक्षता एक महत्वपूर्ण चिंता है। आपकी सूची कितनी बड़ी है कि इससे फर्क पड़ता है?
बरमार


2
आपकी समस्या के वास्तविक उदाहरणों पर आँकड़े किए बिना, आप कुछ भी नहीं जान पाएंगे। इसमें "प्रोग्रामिंग इन आवक" आदि की तुलना करना शामिल है। यदि आंकड़े बहुत महंगे हैं, तो दक्षता की तलाश करना शायद इसके लायक नहीं है।
डेविड टोनहोफर

2
लेवी, वास्तव में आपकी परिभाषा में "कुशल" तरीका क्या है? आप पुनरावृति का एक तेज़ तरीका खोजना चाहते हैं?
सर्गी कोलोडियाज़नी

जवाबों:


18

के साथ बहुत सरल है awk। इससे आपको किसी भी लम्बाई के इनपुट के लिए हर चौथे क्षेत्र का मान मिलेगा:

$ awk -F' ' '{for( i=1;i<=NF;i+=3) { printf( "%s%s", $i, OFS ) }; printf( "\n" ) }' <<< $list
1 5 6 9 15

यह काम करता है बिल्ट-इन awkवैरिएबल जैसे कि NF(रिकॉर्ड में फ़ील्ड्स की संख्या) का लाभ उठाना , और कुछ सरल forलूपिंग करके फ़ील्ड्स के साथ पुनरावृति करना जो आप चाहते हैं कि आप समय से पहले पता करने की आवश्यकता के बिना कि कितने होंगे।

या, यदि आप वास्तव में केवल उन विशिष्ट क्षेत्रों को अपने उदाहरण में निर्दिष्ट करना चाहते हैं:

$ awk -F' ' '{ print $1, $4, $7, $10, $13 }' <<< $list
1 5 6 9 15

दक्षता के बारे में सवाल के लिए, सबसे सरल मार्ग यह या आपके प्रत्येक अन्य तरीकों का परीक्षण करना होगा और timeयह दिखाने के लिए उपयोग करना होगा कि इसमें कितना समय लगता है; आप यह भी देख सकते straceहैं कि सिस्टम किस तरह से कॉल प्रवाहित करता है। timeजैसा दिखता है उसका उपयोग :

$ time ./script.sh

real    0m0.025s
user    0m0.004s
sys     0m0.008s

आप अलग-अलग तरीकों के बीच उस आउटपुट की तुलना कर सकते हैं यह देखने के लिए कि समय के मामले में सबसे कुशल क्या है; अन्य उपकरणों का उपयोग अन्य दक्षता मीट्रिक के लिए किया जा सकता है।


1
अच्छा बिंदु, @ मिचेलहोमर; मैंने "कैसे मैं यह निर्धारित कर सकता हूं कि कौन सी विधि सबसे कुशल है " के प्रश्न को संबोधित करते हुए एक तरफ जोड़ दिया है ।
डोपघोटी

2
@LeviUzodike echoबनाम <<<, "समान" एक शब्द के बारे में बहुत मजबूत है। आप कह सकते हैं कि stuff <<< "$list"लगभग समान है printf "%s\n" "$list" | stuffechoबनाम के बारे में printf, मैं आपको इस जवाब पर
जोएल

5
@ डोपघोटी दरअसल यह करता है। <<<अंत में एक नई पंक्ति जोड़ता है। यह $()एक नई पंक्ति को अंत से हटाने के तरीके के समान है । ऐसा इसलिए है क्योंकि लाइनों को नए सिरे से समाप्त किया जाता है। <<<एक पंक्ति के रूप में एक अभिव्यक्ति खिलाती है, इसलिए इसे एक नई पंक्ति द्वारा समाप्त किया जाना चाहिए। "$()"रेखाएँ लेती हैं और उन्हें एक तर्क के रूप में प्रदान करती हैं, इसलिए यह समाप्त होने वाली न्यूलाइन को हटाकर परिवर्तित करने के लिए समझ में आता है।
जोएल

3
@LeviUzodike awk एक बहुत ही सराहनीय उपकरण है। यह सभी प्रकार की जटिल समस्याओं को हल करने में आसान बना देगा। खासतौर पर जब आप सीड जैसी किसी चीज़ के लिए एक जटिल रेक्स लिखने की कोशिश कर रहे हों, तो आप अक्सर इसे अजीब तरीके से लिखने के बजाय घंटों बचा सकते हैं। इसे सीखने से बड़े लाभांश प्राप्त होंगे।
जो

1
@LeviUzodike: हाँ awkएक स्टैंड-अलोन बाइनरी है जिसे शुरू करना है। पर्ल या विशेष रूप से पायथन के विपरीत, awk दुभाषिया जल्दी से शुरू हो जाता है (अभी भी सभी सामान्य डायनेमिक लिंकर ओवरहेड काफी कुछ सिस्टम कॉल करता है, लेकिन awk केवल libc / libm और libdl का उपयोग करता है। जैसे straceawk स्टार्टअप के सिस्टम-कॉल की जांच करने के लिए उपयोग )। । कई गोले (जैसे बाश) बहुत धीमी गति से होते हैं, इसलिए एक अजीब प्रक्रिया को फायर करना एक सूची में टोकन पर लूपिंग से भी तेज हो सकता है, जो शेल-इन के साथ छोटे-ईश सूची आकारों के लिए भी बनाया गया है। और कभी-कभी आप एक लिख सकते हैं #!/usr/bin/awkस्क्रिप्ट के बजाय एक की #!/bin/shस्क्रिप्ट।
पीटर कॉर्ड्स

35
  • सॉफ्टवेयर अनुकूलन का पहला नियम: नहीं

    जब तक आप जानते हैं कि कार्यक्रम की गति एक मुद्दा है, इस बारे में सोचने की कोई आवश्यकता नहीं है कि यह कितना तेज है। यदि आपकी सूची उस लंबाई के बारे में है या सिर्फ ~ 100-1000 आइटम लंबे हैं, तो आप शायद यह भी नोटिस नहीं करेंगे कि इसमें कितना समय लगता है। एक मौका है कि आप अनुकूलन के बारे में सोचने में अधिक समय बिता रहे हैं इससे क्या अंतर होगा।

  • दूसरा नियम: उपाय

    यह पता लगाने का निश्चित तरीका है, और वह जो आपके सिस्टम के लिए उत्तर देता है। विशेष रूप से गोले के साथ, बहुत सारे हैं, और वे सभी समान नहीं हैं। आपके लिए एक शेल का उत्तर लागू नहीं हो सकता है।

    बड़े कार्यक्रमों में, प्रोफाइलिंग यहाँ भी जाती है। सबसे धीमा हिस्सा वह नहीं हो सकता है जिसे आप सोचते हैं कि यह है।

  • तीसरा, शेल स्क्रिप्ट ऑप्टिमाइज़ेशन का पहला नियम: शेल का उपयोग न करें

    हाँ सच में। कई गोले तेजी से नहीं बने हैं (क्योंकि बाहरी कार्यक्रमों को लॉन्च करने की आवश्यकता नहीं है), और वे हर बार स्रोत कोड की पंक्तियों को फिर से पार्स कर सकते हैं।

    इसके बजाय awk या Perl जैसी किसी चीज़ का उपयोग करें। एक तुच्छ माइक्रो-बेंचमार्क में मैंने किया, awkएक साधारण लूप (I / O के बिना) चलाने में किसी भी सामान्य शेल की तुलना में दर्जनों गुना तेज था।

    हालांकि, यदि आप शेल का उपयोग करते हैं, तो बाहरी कमांड के बजाय शेल के बिलिन फ़ंक्शन का उपयोग करें। यहां, आप उपयोग कर रहे हैं exprजो मेरे सिस्टम पर मिले किसी भी गोले में नहीं बनाया गया है, लेकिन जिसे मानक अंकगणितीय विस्तार के साथ बदला जा सकता है। जैसे वेतन वृद्धि के i=$((i+1))बदले । अंतिम उदाहरण में आपका उपयोग मानक पैरामीटर विस्तार के साथ भी बदली जा सकता है।i=$(expr $i + 1)icut

    यह भी देखें: पाठ को खराब अभ्यास माना जाने वाले प्रक्रिया को शेल लूप का उपयोग क्यों किया जाता है?

चरण # 1 और # 2 आपके प्रश्न पर लागू होना चाहिए।


12
# 0, अपने विस्तार :-) बोली
Kusalananda

8
ऐसा नहीं है कि awkलूप आवश्यक रूप से शेल लूप से बेहतर या खराब हैं। यह है कि शेल वास्तव में कमांड चलाने पर और प्रक्रियाओं से इनपुट और आउटपुट को निर्देशित करने के लिए अच्छा है, और स्पष्ट रूप से बल्कि हर चीज के बारे में स्पष्ट है; जबकि टूल जैसे उपकरण टेक्स्ट डेटा को संसाधित करने में शानदारawk होते हैं , क्योंकि पहली बार में गोले और उपकरण जैसे (क्रमशः) बने होते हैं। awk
डोपघोटी

2
@ डोपघोटी, गोले, हालांकि बहुत धीमी गति से लगते हैं। कुछ बहुत ही सरल होते हैं, लूप्स लगते हैं> 25 गुना धीमी गति dashसे gawk, और dashसबसे तेज शेल जो मैंने परीक्षण किया ...
ilkachachu

1
@ जो, यह है :) dashऔर busyboxसमर्थन नहीं करते (( .. ))- मुझे लगता है कि यह एक गैर-मानक विस्तार है। ++यह भी स्पष्ट रूप से आवश्यक नहीं के रूप में उल्लेख किया है, जहाँ तक मैं बता सकता हूँ, i=$((i+1))या : $(( i += 1))सुरक्षित हैं।
ilkachachu

1
पुन "और अधिक समय सोच" : यह एक महत्वपूर्ण कारक neglects। यह कितनी बार चलता है, और कितने उपयोगकर्ताओं के लिए? यदि कोई प्रोग्राम 1 सेकंड बर्बाद करता है, जिसे प्रोग्रामर 30 मिनट के लिए सोचकर तय कर सकता है, तो यह समय की बर्बादी हो सकती है यदि केवल एक उपयोगकर्ता है जो इसे एक बार चलाने जा रहा है। दूसरी ओर यदि एक मिलियन उपयोगकर्ता हैं, तो वह एक मिलियन सेकंड या 11 दिनों का उपयोगकर्ता समय है। यदि कोड ने एक मिलियन उपयोगकर्ताओं का एक मिनट बर्बाद किया, तो यह उपयोगकर्ता के लगभग 2 वर्ष का समय होगा।
अगस्त

13

मैं केवल इस उत्तर में कुछ सामान्य सलाह देने जा रहा हूं, और बेंचमार्क नहीं। बेंचमार्क प्रदर्शन के बारे में मज़बूती से सवालों के जवाब देने का एकमात्र तरीका है। लेकिन जब से आप यह नहीं कहते हैं कि आप कितना डेटा जोड़-तोड़ कर रहे हैं और आप कितनी बार इस ऑपरेशन को करते हैं, एक उपयोगी बेंचमार्क करने का कोई तरीका नहीं है। 10 वस्तुओं के लिए क्या अधिक कुशल है और 1000000 वस्तुओं के लिए अधिक कुशल क्या है यह अक्सर समान नहीं होता है।

अंगूठे के एक सामान्य नियम के रूप में, बाहरी शेल को लागू करना शुद्ध शेल निर्माणों के साथ कुछ करने की तुलना में अधिक महंगा है, जब तक कि शुद्ध शेल कोड में लूप शामिल नहीं होता है। दूसरी ओर, एक शेल लूप जो एक बड़ी स्ट्रिंग या स्ट्रिंग की एक बड़ी मात्रा पर पुनरावृत्ति करता है, विशेष प्रयोजन उपकरण के एक आह्वान की तुलना में धीमा होने की संभावना है। उदाहरण के लिए, आपका लूप इनवोकिंग cutअभ्यास में अच्छी तरह से धीमा हो सकता है, लेकिन यदि आप एक एकल cutआह्वान के साथ पूरे काम को करने का एक तरीका ढूंढते हैं, तो शेल में स्ट्रिंग हेरफेर के साथ एक ही चीज़ करने की तुलना में तेज़ होने की संभावना है।

ध्यान दें कि सिस्टम के बीच कटऑफ बिंदु बहुत भिन्न हो सकता है। यह कर्नेल पर निर्भर कर सकता है कि कर्नेल के शेड्यूलर को कैसे कॉन्फ़िगर किया गया है, बाह्य निष्पादनयोग्य युक्त फाइलसिस्टम पर, इस समय कितना CPU बनाम मेमोरी प्रेशर है, और कई अन्य कारक हैं।

exprयदि आप प्रदर्शन के बारे में चिंतित हैं तो अंकगणित करने के लिए कॉल न करें । वास्तव में, exprअंकगणितीय प्रदर्शन करने के लिए कॉल न करें । शेल में अंतर्निहित अंकगणित होते हैं, जो स्पष्ट और आह्वान से तेज होते हैं expr

आपको लगता है कि आप bash कंस्ट्रक्शन का उपयोग कर रहे हैं, जो कि bash का उपयोग नहीं कर रहा है। तो पृथ्वी पर आप एक सरणी का उपयोग क्यों नहीं करेंगे? एक सरणी सबसे प्राकृतिक समाधान है, और यह सबसे तेज़, भी होने की संभावना है। ध्यान दें कि सरणी सूचकांक 0 से शुरू होते हैं।

list=(1 2 3 5 9 8 6 90 84 9 3 2 15 75 55)
for ((count = 0; count += 3; count < ${#list[@]})); do
  echo "${list[$count]}"
done

यदि आप अपने सिस्टम को डैश के shबजाय डैश या ksh करते हैं, तो आपकी स्क्रिप्ट अच्छी तरह से तेज़ हो सकती है । यदि आप श का उपयोग करते हैं, तो आपको नामित सरणियाँ नहीं मिलती हैं, लेकिन आपको अभी भी सरणी को स्थितीय मापदंडों में से एक मिलता है, जिसे आप सेट कर सकते हैं set। एक तत्व को उस स्थिति में एक्सेस करने के लिए जिसे रनटाइम तक ज्ञात नहीं है, आपको उपयोग करने की आवश्यकता है eval(चीजों को ठीक से उद्धृत करने का ध्यान रखें)।

# List elements must not contain whitespace or ?*\[
list='1 2 3 5 9 8 6 90 84 9 3 2 15 75 55'
set $list
count=1
while [ $count -le $# ]; do
  eval "value=\${$count}"
  echo "$value"
  count=$((count+1))
done

यदि आप कभी भी सरणी को एक बार एक्सेस करना चाहते हैं और बाएं से दाएं (कुछ मानों को छोड़ते हुए) जा रहे हैं, तो आप shiftपरिवर्तनीय सूचकांकों के बजाय उपयोग कर सकते हैं ।

# List elements must not contain whitespace or ?*\[
list='1 2 3 5 9 8 6 90 84 9 3 2 15 75 55'
set $list
while [ $# -ge 1 ]; do
  echo "$1"
  shift && shift && shift
done

कौन सा दृष्टिकोण तेज है यह शेल पर और तत्वों की संख्या पर निर्भर करता है।

एक अन्य संभावना स्ट्रिंग प्रसंस्करण का उपयोग करना है। इसका फायदा यह है कि स्थितिगत मापदंडों का उपयोग न करने के लिए, इसलिए आप उन्हें किसी और चीज़ के लिए उपयोग कर सकते हैं। यह बड़ी मात्रा में डेटा के लिए धीमा होगा, लेकिन यह डेटा की छोटी मात्रा के लिए ध्यान देने योग्य अंतर करने की संभावना नहीं है।

# List elements must be separated by a single space (not arbitrary whitespace)
list='1 2 3 5 9 8 6 90 84 9 3 2 15 75 55'
while [ -n "$list" ]; do
  echo "${list% *}"
  case "$list" in *\ *\ *\ *) :;; *) break;; esac
  list="${list#* * * }"
done

" दूसरी ओर, एक शेल लूप जो एक बड़ी स्ट्रिंग या स्ट्रिंग की एक बड़ी मात्रा पर पुनरावृत्ति करता है, एक विशेष प्रयोजन उपकरण के एक आह्वान की तुलना में धीमा होने की संभावना है " लेकिन क्या होगा अगर उस उपकरण में जाग की तरह लूप है? @ikachach ने कहा कि awk loops तेज हैं, लेकिन क्या आप कहेंगे कि <1000 फ़ील्ड्स के माध्यम से पुनरावृति करने के लिए, तेज लूप्स का लाभ awk को कॉल करने की लागत से आगे नहीं बढ़ेगा क्योंकि यह एक बाहरी कमांड है (यह मानते हुए कि मैं शेल में समान कार्य कर सकता हूं केवल आदेशों में निर्मित) के उपयोग के साथ छोरों)?
लेवि उज़ोडाइक

@LeviUzodike कृपया मेरे उत्तर के पहले पैराग्राफ को फिर से पढ़ें।
गाइल्स 'एसओ- बुराई पर रोक'

तुम भी बदल सकते shift && shift && shiftके साथ shift 3अपने तीसरे उदाहरण में - जब तक खोल आप उपयोग कर रहे इसका समर्थन नहीं करता।
जो

2
@ जोए वास्तव में, नहीं। shift 3यदि बहुत कम तर्क शेष होते तो विफल हो जाते। आपको कुछ इस तरह की आवश्यकता होगीif [ $# -gt 3 ]; then shift 3; else set --; fi
गाइल्स एसओ- बुराई को रोकना '

3

awkएक बहुत अच्छा विकल्प है, यदि आप अपने सभी प्रसंस्करण को Awk स्क्रिप्ट के अंदर कर सकते हैं। अन्यथा, आप केवल अन्य उपयोगिताओं के लिए Awk आउटपुट पाइपिंग को समाप्त करते हैं, के प्रदर्शन लाभ को नष्ट करते हैं awk

bashकिसी सरणी पर पुनरावृत्ति भी महान है, यदि आप अपनी पूरी सूची को सरणी के अंदर फिट कर सकते हैं (जो कि आधुनिक गोले के लिए संभवतः एक गारंटी है) और आप सरणी वाक्यविन्यास जिमनास्टिक को बुरा नहीं मानते।

हालांकि, एक पाइपलाइन दृष्टिकोण:

xargs -n3 <<< "$list" | while read -ra a; do echo $a; done | grep 9

कहा पे:

  • xargs व्हाट्सएप-अलग-अलग सूची को तीन के बैचों में बांटता है, प्रत्येक नई-पंक्ति अलग हो जाती है
  • while read उस सूची का उपभोग करता है और प्रत्येक समूह के पहले कॉलम को आउटपुट करता है
  • grep पहला कॉलम फ़िल्टर करता है (मूल सूची में प्रत्येक तीसरे स्थान के अनुरूप)

मेरी राय में, समझ में सुधार। लोग पहले से ही जानते हैं कि ये उपकरण क्या करते हैं, इसलिए बाएं से दाएं पढ़ना आसान है और क्या होने जा रहा है इसके बारे में कारण। यह दृष्टिकोण स्पष्ट रूप से स्ट्राइड लंबाई ( -n3) और फ़िल्टर पैटर्न ( 9) को भी दस्तावेज़ित करता है , इसलिए इसे अस्थिर करना आसान है:

count=3
find=9
xargs -n "$count" <<< "$list" | while read -ra a; do echo $a; done | grep "$find"

जब हम "दक्षता" के प्रश्न पूछते हैं, तो "कुल जीवनकाल दक्षता" के बारे में सोचना सुनिश्चित करें। उस गणना में कोड को कार्यशील रखने के लिए अनुरक्षकों का प्रयास शामिल है, और हम मांस-बैग पूरे ऑपरेशन में सबसे कम कुशल मशीन हैं।


2

शायद यह?

cut -d' ' -f1,4,7,10,13 <<<$list
1 5 6 9 15

क्षमा करें, मैं पहले स्पष्ट नहीं था, लेकिन मैं सूची की लंबाई को जाने बिना उन पदों पर संख्या प्राप्त करने में सक्षम होना चाहता था। लेकिन धन्यवाद, मैं भूल गया कि कटौती कर सकता है।
लेवि उज़ोडिके

1

यदि आप कुशल होना चाहते हैं तो शेल कमांड का उपयोग न करें। अपने आप को पाइप, पुनर्निर्देशन, प्रतिस्थापन आदि और कार्यक्रमों तक सीमित रखें। यही कारण है कि xargsऔर parallelउपयोगिताओं मौजूद हैं - क्योंकि बैश जबकि लूप अक्षम और बहुत धीमी गति से होते हैं। अंतिम उपाय के रूप में बैश लूप का ही उपयोग करें।

list="1 ant bat 5 cat dingo 6 emu fish 9 gecko hare 15 i j"
if 
    <<<"$list" tr -d -s '[0-9 ]' | 
    tr -s ' ' | tr ' ' '\n' | 
    grep -q -x '9'
then
    found=true
else 
    found=false
fi
echo ${found} 

लेकिन आपको अच्छे के साथ शायद कुछ तेज होना चाहिए awk


क्षमा करें, मैं पहले स्पष्ट नहीं था, लेकिन मैं एक ऐसे समाधान की तलाश में था जो केवल सूची में उनकी स्थिति के आधार पर मूल्यों को निकालने में सक्षम हो। मैंने सिर्फ इस तरह से मूल सूची बनाई क्योंकि मैं चाहता था कि यह उन मूल्यों को स्पष्ट करे जो मैं चाहता था।
लेवि उज़ोडिके

1

मेरी राय में सबसे स्पष्ट समाधान (और शायद सबसे अधिक प्रदर्शन करने वाला) RS और ORS awk चर का उपयोग करना है:

awk -v RS=' ' -v ORS=' ' 'NR % 3 == 1' <<< "$list"

1
  1. GNU sed और POSIX शेल स्क्रिप्ट का उपयोग करना :

    echo $(printf '%s\n' $list | sed -n '1~3p')
  2. या साथ bashके पैरामीटर प्रतिस्थापन :

    echo $(sed -n '1~3p' <<< ${list// /$'\n'})
  3. गैर- GNU ( यानी POSIX ) sed, और bash:

    sed 's/\([^ ]* \)[^ ]* *[^ ]* */\1/g' <<< "$list"

    या अधिक, दोनों POSIX sed और शेल स्क्रिप्ट का उपयोग करते हुए :

    echo "$list" | sed 's/\([^ ]* \)[^ ]* *[^ ]* */\1/g'

इनमें से किसी का आउटपुट:

1 5 6 9 15
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.