पाठ को संसाधित करने के लिए शेल लूप का उपयोग करना बुरा व्यवहार क्यों माना जाता है?


196

POSIX गोले में पाठ को आमतौर पर बुरा व्यवहार करने के लिए थोड़ी देर के लूप का उपयोग किया जाता है?

जैसा कि स्टीफन चेज़लस ने बताया , शेल लूप का उपयोग न करने के कुछ कारण वैचारिक , विश्वसनीयता , सुगमता , प्रदर्शन और सुरक्षा हैं

यह उत्तर विश्वसनीयता और सुगमता के पहलुओं की व्याख्या करता है :

while IFS= read -r line <&3; do
  printf '%s\n' "$line"
done 3< "$InputFile"

के लिए प्रदर्शन , whileपाश और पढ़ने में काफी धीमी गति से जब एक फ़ाइल या एक पाइप से पढ़ रहे हैं, क्योंकि पढ़ने के खोल में निर्मित एक समय में एक चरित्र पढ़ता है।

वैचारिक और सुरक्षा पहलुओं के बारे में कैसे ?


संबंधित (सिक्के का दूसरा पहलू): इतनी जल्दी फाइल कैसे yesलिखता है?
वाइल्डकार्ड

1
निर्मित शेल एक बार में एक वर्ण नहीं पढ़ता है, यह एक बार में एक पंक्ति पढ़ता है। wiki.bash-hackers.org/commands/builtin/read
A.Danischewski

@ A.Danischewski: यह आपके शेल पर निर्भर करता है। इसमें bash, यह एक समय में एक बफर आकार पढ़ता है, dashउदाहरण के लिए प्रयास करें । यह भी देखें unix.stackexchange.com/q/209123/38906
cuonglm

जवाबों:


256

हां, हम कई चीजों को देखते हैं जैसे:

while read line; do
  echo $line | cut -c3
done

या खराब:

for line in `cat file`; do
  foo=`echo $line | awk '{print $2}'`
  echo whatever $foo
done

(हँसो मत, मैंने उनमें से कई को देखा है)।

आम तौर पर शेल स्क्रिप्टिंग शुरुआती से। सी या पाइथन जैसी अनिवार्य भाषाओं में आप जो करते हैं, उसके वे भोले शाब्दिक अनुवाद हैं, लेकिन ऐसा नहीं है कि आप कैसे गोले में काम करते हैं, और वे उदाहरण बहुत ही अक्षम हैं, पूरी तरह से अविश्वसनीय हैं (संभावित रूप से सुरक्षा के मुद्दों के लिए अग्रणी), और यदि आप कभी भी प्रबंधन करते हैं अधिकांश बग को ठीक करने के लिए, आपका कोड अवैध हो जाता है।

सैद्धांतिक रूप

सी या अधिकांश अन्य भाषाओं में, बिल्डिंग ब्लॉक कंप्यूटर निर्देशों से सिर्फ एक स्तर ऊपर हैं। आप अपने प्रोसेसर को बताएं कि आगे क्या करना है और फिर क्या करना है। आप अपने प्रोसेसर को हाथ से लेते हैं और इसे माइक्रो-मैनेज करते हैं: आप उस फ़ाइल को खोलते हैं, आप पढ़ते हैं कि कई बाइट्स, आप ऐसा करते हैं, आप इसके साथ ऐसा करते हैं।

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

यूनिक्स द्वारा पेश की गई महान चीजों में से एक पाइप था और उन डिफ़ॉल्ट स्टड / stdout / stderr धाराएं जो सभी कमांड डिफ़ॉल्ट रूप से संभालती हैं।

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

आपको एक कटिंग टूल और एक ट्रांसपेरेंट टूल मिला है, और आप बस कर सकते हैं:

cut -c4-5 < in | tr a b > out

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

एक उपकरण को शामिल करना हालांकि एक लागत है (और हम प्रदर्शन बिंदु पर इसे विकसित करेंगे)। उन उपकरणों को सी में हजारों निर्देशों के साथ लिखा जा सकता है। एक प्रक्रिया बनानी होगी, उपकरण को लोड करना होगा, आरंभ करना होगा, फिर साफ किया जाएगा, प्रक्रिया नष्ट हो जाएगी और इंतजार करना होगा।

आमंत्रित करना cutरसोई के दराज को खोलने के समान है, चाकू ले लो, इसका उपयोग करें, इसे धो लें, इसे सूखा दें, इसे वापस दराज में डालें। जब तुम करोगे:

while read line; do
  echo $line | cut -c3
done < file

यह फ़ाइल की प्रत्येक पंक्ति के लिए है, readरसोई दराज से उपकरण प्राप्त करना (एक बहुत ही भद्दा क्योंकि यह उसके लिए डिज़ाइन नहीं किया गया है ), एक पंक्ति पढ़ें, अपना पढ़ा उपकरण धोएं, इसे वापस दराज में रखें। फिर echoऔर cutउपकरण के लिए एक बैठक निर्धारित करें, उन्हें दराज से प्राप्त करें, उन्हें आह्वान करें, उन्हें धोएं, उन्हें सूखा दें, उन्हें वापस दराज में रखें और इसी तरह।

उन उपकरणों में से कुछ ( readऔर echo) अधिकांश गोले में बनाए गए हैं, लेकिन यह मुश्किल से यहाँ फर्क पड़ता है echoऔर cutअभी भी अलग-अलग प्रक्रियाओं में चलाने की आवश्यकता है।

यह एक प्याज को काटने जैसा है लेकिन अपने चाकू को धोने और इसे प्रत्येक स्लाइस के बीच किचन दराज में रख दें।

यहां स्पष्ट तरीका यह है कि आप अपने cutउपकरण को दराज से प्राप्त करें , अपने पूरे प्याज को स्लाइस करें और पूरी नौकरी करने के बाद इसे वापस दराज में रख दें।

IOW, गोले में, विशेष रूप से पाठ को संसाधित करने के लिए, आप संभव के रूप में कुछ उपयोगिताओं को आमंत्रित करते हैं और उन्हें कार्य में सहयोग करते हैं, क्रम में हजारों उपकरण नहीं चलाते हैं ताकि अगले एक को चलाने से पहले शुरू करने, चलाने, साफ करने के लिए प्रतीक्षा करें।

आगे ब्रूस के ठीक जवाब में पढ़ना । गोले में निम्न-स्तरीय पाठ प्रसंस्करण आंतरिक उपकरण (शायद को छोड़कर zsh) सीमित, बोझिल हैं, और आम तौर पर सामान्य पाठ प्रसंस्करण के लिए फिट नहीं होते हैं।

प्रदर्शन

जैसा कि पहले कहा गया था, एक कमांड को चलाने में एक लागत है। एक बड़ी लागत अगर वह कमांड नहीं है, लेकिन भले ही वे बिलिन हैं, तो लागत बड़ी है।

और गोले को इस तरह चलाने के लिए डिज़ाइन नहीं किया गया है, उन्हें प्रदर्शनशील प्रोग्रामिंग भाषा होने का कोई दिखावा नहीं है। वे नहीं हैं, वे सिर्फ कमांड लाइन दुभाषिए हैं। इसलिए, इस मोर्चे पर थोड़ा अनुकूलन किया गया है।

इसके अलावा, गोले अलग-अलग प्रक्रियाओं में कमांड चलाते हैं। उन बिल्डिंग ब्लॉक्स में एक आम मेमोरी या स्टेट शेयर नहीं होता है। जब आप C fgets()या fputs()C में करते हैं, तो stdio में एक फंक्शन होता है। stdio इनपुट और आउटपुट के लिए सभी stdio फ़ंक्शंस के लिए आंतरिक बफ़र्स रखता है, महंगा सिस्टम कॉल करने से बचने के लिए अक्सर।

इसी भी builtin खोल उपयोगिताओं ( read, echo, printf) ऐसा नहीं कर सकते। readएक पंक्ति को पढ़ने के लिए है। यदि यह न्यूलाइन कैरेक्टर को पढ़ता है, तो इसका मतलब है कि आपके द्वारा चलाया जाने वाला अगला कमांड इसे याद करेगा। तो readएक समय में इनपुट एक बाइट को पढ़ना है (कुछ कार्यान्वयन में एक अनुकूलन है यदि इनपुट एक नियमित फ़ाइल है जिसमें वे विखंडू पढ़ते हैं और वापस चाहते हैं, लेकिन यह केवल नियमित फ़ाइलों के लिए काम करता है और bashउदाहरण के लिए केवल 128 बाइट विखंडू पढ़ता है जो कि है अभी भी पाठ उपयोगिताओं की तुलना में बहुत कम है)।

आउटपुट पक्ष पर समान, echoइसके आउटपुट को केवल बफर नहीं कर सकता, इसे सीधे आउटपुट करना होगा क्योंकि आपके द्वारा चलाया जाने वाला अगला कमांड उस बफर को साझा नहीं करेगा।

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

उस while readलूप और (माना जाता है) के बराबर cut -c3 < file, मेरे त्वरित परीक्षण में, मेरे परीक्षणों में लगभग 40000 का सीपीयू समय अनुपात है (एक सेकंड बनाम आधा दिन)। लेकिन भले ही आप केवल शेल बिल्डरों का उपयोग करें:

while read line; do
  echo ${line:2:1}
done

(यहां bash), वह अभी भी लगभग 1: 600 (एक सेकंड बनाम 10 मिनट) है।

विश्वसनीयता / स्पष्टता

उस कोड को प्राप्त करना बहुत कठिन है। मैंने जो उदाहरण दिए वे बहुत बार जंगली में देखे गए हैं, लेकिन उनके पास कई कीड़े हैं।

readएक आसान उपकरण है जो कई अलग-अलग काम कर सकता है। यह उपयोगकर्ता से इनपुट पढ़ सकता है, इसे विभिन्न चर में स्टोर करने के लिए शब्दों में विभाजित कर सकता है। read lineकरता नहीं इनपुट की एक पंक्ति पढ़ते हैं, या हो सकता है यह एक बहुत ही विशेष तरीके से एक लाइन पढ़ता है। यह वास्तव में इनपुट से उन शब्दों को पढ़ता है जिनके द्वारा अलग किए गए शब्द $IFSऔर जहां बैकस्लैश का उपयोग विभाजकों या न्यूलाइन वर्ण से बचने के लिए किया जा सकता है।

$IFSजैसे इनपुट पर डिफ़ॉल्ट मान के साथ:

   foo\/bar \
baz
biz

read lineस्टोर करेगा "foo/bar baz"में $line, नहीं " foo\/bar \"के रूप में आप उम्मीद थी।

एक पंक्ति पढ़ने के लिए, आपको वास्तव में आवश्यकता है:

IFS= read -r line

यह बहुत सहज नहीं है, लेकिन यह जिस तरह से है, याद है कि गोले उस तरह से इस्तेमाल करने के लिए नहीं थे।

उसी के लिए echoechoदृश्यों का विस्तार करता है। आप किसी यादृच्छिक फ़ाइल की सामग्री की तरह मनमानी सामग्री के लिए इसका उपयोग नहीं कर सकते। आपको printfइसके बजाय यहाँ की आवश्यकता है।

और निश्चित रूप से, आपके चर को उद्धृत करने की विशिष्ट भूल है जो हर कोई गिर जाता है। तो यह अधिक है:

while IFS= read -r line; do
  printf '%s\n' "$line" | cut -c3
done < file

अब, कुछ और चेतावनी:

  • इसके अलावा zsh, यदि इनपुट में NUL वर्ण नहीं है तो काम नहीं करता है जबकि कम से कम GNU टेक्स्ट उपयोगिताओं में समस्या नहीं होगी।
  • यदि अंतिम न्यूलाइन के बाद डेटा है, तो इसे छोड़ दिया जाएगा
  • लूप के अंदर, स्टड को पुनर्निर्देशित किया जाता है, इसलिए आपको ध्यान देने की आवश्यकता है कि इसमें दिए गए आदेश स्टड से नहीं पढ़ते हैं।
  • छोरों के भीतर आदेशों के लिए, हम ध्यान नहीं दे रहे हैं कि वे सफल होते हैं या नहीं। आमतौर पर, त्रुटि (डिस्क पूर्ण, त्रुटियों को पढ़ें ...) स्थितियों को खराब संभाला जाएगा, आमतौर पर सही समकक्ष के मुकाबले अधिक खराब ।

यदि हम उपरोक्त कुछ मुद्दों को संबोधित करना चाहते हैं, तो यह हो जाता है:

while IFS= read -r line <&3; do
  {
    printf '%s\n' "$line" | cut -c3 || exit
  } 3<&-
done 3< file
if [ -n "$line" ]; then
    printf '%s' "$line" | cut -c3 || exit
fi

वह कम और कम सुपाठ्य होता जा रहा है।

तर्कों के माध्यम से आदेश देने या चर में अपने उत्पादन को पुनः प्राप्त करने के लिए डेटा पारित करने के साथ कई अन्य मुद्दे हैं:

  • तर्कों के आकार पर सीमा (कुछ पाठ उपयोगिता कार्यान्वयन के रूप में अच्छी तरह से वहाँ एक सीमा है, हालांकि उन तक पहुँचने के प्रभाव आम तौर पर कम समस्याग्रस्त हैं)
  • एनयूएल चरित्र (पाठ उपयोगिताओं के साथ एक समस्या भी)।
  • विकल्प के रूप में लिया गया तर्क जब वे -(या +कभी-कभी) शुरू करते हैं
  • आम तौर पर उन लूप्स में उपयोग किए जाने वाले विभिन्न कमांडों के विभिन्न quirks expr, test...
  • सीमित (सीमित) विभिन्न गोले के पाठ हेरफेर ऑपरेटर जो असंगत तरीकों से बहु-बाइट वर्णों को संभालते हैं।
  • ...

सुरक्षा के विचार

जब आप शेल चर और कमांड के तर्क के साथ काम करना शुरू करते हैं, तो आप एक खदान क्षेत्र में प्रवेश कर रहे हैं।

यदि आप अपने चरों को उद्धृत करना भूल जाते हैं, विकल्प मार्कर के अंत को भूल जाते हैं , तो मल्टी-बाइट वर्ण (इन दिनों आदर्श) के साथ स्थानों में काम करते हैं, तो आप बग का परिचय देना निश्चित करते हैं जो जल्द या बाद में भेद्यता बन जाएगा।

जब आप लूप का उपयोग करना चाह सकते हैं।

TBD


24
स्पष्ट (विशद), पठनीय और अत्यंत सहायक। एक बार फिर आपका धन्यवाद। यह वास्तव में शेल स्क्रिप्टिंग और प्रोग्रामिंग के बीच मूलभूत अंतर के लिए मैंने इंटरनेट पर कहीं भी देखा सबसे अच्छा स्पष्टीकरण है।
वाइल्डकार्ड

2
यह इस तरह के पोस्ट हैं जो शुरुआती लोगों को शेल लिपियों के बारे में जानने में मदद करते हैं और देखते हैं कि यह सूक्ष्म अंतर है। आपको शून्य न मिलने के लिए $ {VAR: -default_value} के रूप में संदर्भित चर जोड़ना चाहिए। और एक गैर-परिभाषित मूल्य का संदर्भ देते समय आप पर चिल्लाना सेट करें।
अहस्ताक्षरितो

6
@ A.Danischewski, मुझे लगता है कि आप इस बिंदु को याद कर रहे हैं। cutउदाहरण के लिए हां कुशल है। cut -f1 < a-very-big-fileकुशल है, उतना ही कुशल है जितना कि आप अगर आप इसे सी में लिखेंगे तो यह बहुत ही अक्षम और त्रुटि प्रवण है, शेल लूप में ए cutकी प्रत्येक पंक्ति के लिए इनवाइट कर a-very-big-fileरहा है जो इस उत्तर में बनाया जा रहा है। अनावश्यक कोड लिखने के बारे में आपके अंतिम कथन के साथ जो मुझे लगता है कि शायद मुझे आपकी टिप्पणी समझ में नहीं आती है।
स्टीफन चेजालस

5
"45 वर्षों में, हमने कमांड की शक्ति का उपयोग करने के लिए एपीआई से बेहतर नहीं पाया है और उन्हें एक कार्य में सहयोग करना है।" - वास्तव में, PowerShell, ने एक के लिए, बाइट धाराओं के बजाय संरचित डेटा के आसपास से गुजरते हुए खतरनाक पार्सिंग समस्या को हल किया है। एकमात्र कारण गोले अभी तक इसका उपयोग नहीं करते हैं (विचार काफी समय से रहा है और मूल रूप से जावा के आसपास कुछ समय में क्रिस्टलीकृत हो गया है जब अब मानक सूची और शब्दकोश कंटेनर प्रकार मुख्यधारा बन गए हैं) उनके अनुरक्षक अभी तक सहमत नहीं हो सकते हैं आम संरचित डेटा प्रारूप का उपयोग करने के लिए (।
ivan_pozdeev

6
@OlivierDulac मुझे लगता है कि थोड़ा हास्य है। वह खंड हमेशा के लिए टीबीडी होगा।
मुरु

43

जहां तक ​​वैचारिक और सुगम्यता की बात है, शेल आमतौर पर फाइलों में रुचि रखते हैं। उनकी "पता करने योग्य इकाई" फ़ाइल है, और "पता" फ़ाइल नाम है। शेल में फ़ाइल अस्तित्व, फ़ाइल प्रकार, फ़ाइल नाम स्वरूपण (ग्लोबिंग के साथ शुरुआत) के लिए सभी प्रकार के परीक्षण हैं। शेल में फ़ाइल सामग्री से निपटने के लिए बहुत कम प्राइमिटिव हैं। शेल प्रोग्रामर्स को फ़ाइल सामग्री से निपटने के लिए एक और कार्यक्रम शुरू करना होगा।

फ़ाइल और फ़ाइल नाम अभिविन्यास के कारण, शेल में पाठ हेरफेर करना वास्तव में धीमा है, जैसा कि आपने नोट किया है, लेकिन एक अस्पष्ट और विपरीत प्रोग्रामिंग शैली की भी आवश्यकता है।


25

कुछ जटिल जवाब हैं, हमारे बीच गीक्स के लिए बहुत सारे दिलचस्प विवरण दे रहे हैं, लेकिन यह वास्तव में काफी सरल है - एक शेल लूप में एक बड़ी फ़ाइल को संसाधित करना बहुत धीमा है।

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

पहले हिस्सों ( initialization) के लिए, यह आमतौर पर मायने नहीं रखता है कि शेल कमांड धीमी हैं - यह केवल कुछ दर्जन कमांड चला रहा है, शायद कुछ छोटे छोरों के साथ। यहां तक ​​कि अगर हम उस हिस्से को अक्षम रूप से लिखते हैं, तो भी आमतौर पर यह आरंभ करने के लिए एक सेकंड से कम समय लेने वाला है, और यह ठीक है - यह केवल एक बार होता है।

लेकिन जब हम बड़ी फ़ाइल है, जो हजारों या लाइनों के लाखों हो सकता था प्रसंस्करण के लिए पर मिलता है, यह है नहीं ठीक खोल स्क्रिप्ट एक दूसरे का एक महत्वपूर्ण अंश के लिए प्रत्येक पंक्ति के लिए (भले ही यह केवल कुछ दर्जन मिलीसेकेंड है), जैसा कि घंटों तक जोड़ सकता है।

जब हमें अन्य उपकरणों का उपयोग करने की आवश्यकता होती है, और यूनिक्स खोल लिपियों की सुंदरता यह है कि वे हमारे लिए ऐसा करना बहुत आसान बनाते हैं।

प्रत्येक पंक्ति को देखने के लिए एक लूप का उपयोग करने के बजाय, हमें कमांड की पाइप लाइन के माध्यम से पूरी फाइल को पास करने की आवश्यकता है । इसका मतलब यह है कि, कमांड हजारों या लाखों बार कॉल करने के बजाय, शेल उन्हें केवल एक बार कॉल करता है। यह सच है कि उन कमांडों में फाइल लाइन-बाय-लाइन को संसाधित करने के लिए लूप होंगे, लेकिन वे शेल स्क्रिप्ट नहीं हैं और उन्हें तेज और कुशल बनाया गया है।

यूनिक्स में सरल से लेकर जटिल तक के कई अद्भुत उपकरण हैं, जिनका उपयोग हम अपनी पाइपलाइन बनाने में कर सकते हैं। मैं आमतौर पर सरल लोगों के साथ शुरू होता हूं, और केवल जब आवश्यक हो तो अधिक जटिल लोगों का उपयोग करता हूं।

मैं मानक उपकरणों के साथ भी चिपके रहने की कोशिश करूंगा जो कि अधिकांश प्रणालियों पर उपलब्ध हैं, और अपने उपयोग को पोर्टेबल रखने की कोशिश करते हैं, हालांकि यह हमेशा संभव नहीं है। और अगर आपकी पसंदीदा भाषा पायथन या रूबी है, तो शायद आप यह सुनिश्चित करने के अतिरिक्त प्रयास को बुरा नहीं मानेंगे कि यह हर उस प्लेटफॉर्म पर स्थापित है जिसे आपके सॉफ़्टवेयर को चलाने की आवश्यकता है :-)

सरल उपकरण शामिल हैं head, tail, grep, sort, cut, tr, sed, join(जब 2 फ़ाइलें विलय), और awkएक-लाइनर्स, कई अन्य लोगों के अलावा। यह आश्चर्यजनक है कि कुछ लोग पैटर्न-मिलान और sedकमांड के साथ क्या कर सकते हैं ।

जब यह अधिक जटिल हो जाता है, और आपको वास्तव में प्रत्येक पंक्ति में कुछ तर्क लागू करने होते हैं, awkतो एक अच्छा विकल्प है - या तो एक-लाइनर (कुछ लोग पूरी awk स्क्रिप्ट को 'एक लाइन' में डालते हैं, हालांकि यह बहुत पठनीय नहीं है) या एक में लघु बाह्य लिपि।

जैसा awkकि एक व्याख्या की गई भाषा है (आपके खोल की तरह), यह आश्चर्यजनक है कि यह लाइन-बाय-लाइन प्रसंस्करण इतनी कुशलता से कर सकता है, लेकिन यह इसके लिए उद्देश्य-निर्मित है और यह वास्तव में बहुत तेज है।

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

और अंत में, अच्छा पुराना सी है, यदि आपको अधिकतम गति और उच्च लचीलेपन की आवश्यकता है (हालांकि पाठ प्रसंस्करण थोड़ा कठिन है)। लेकिन यह संभवतः आपके समय का एक बहुत बुरा उपयोग है कि आप हर अलग-अलग फाइल-प्रोसेसिंग कार्य के लिए एक नया सी प्रोग्राम लिखें। मैं सीएसवी फाइलों के साथ बहुत काम करता हूं, इसलिए मैंने सी में कई सामान्य उपयोगिताओं को लिखा है कि मैं कई अलग-अलग परियोजनाओं में फिर से उपयोग कर सकता हूं। वास्तव में, यह 'सरल, तेज यूनिक्स उपकरण' की सीमा का विस्तार करता है जिसे मैं अपनी शेल स्क्रिप्ट्स से कॉल कर सकता हूं, इसलिए मैं ज्यादातर प्रोजेक्ट्स को केवल स्क्रिप्ट लिखकर संभाल सकता हूं, जो हर बार लिखने और बीस्पोक सी कोड डीबग करने की तुलना में बहुत तेज है!

कुछ अंतिम संकेत:

  • अपनी मुख्य शेल स्क्रिप्ट को शुरू करना न भूलें export LANG=C, या कई उपकरण आपके सादे-पुराने-एएससीआईआई फाइलों को यूनिकोड के रूप में मानेंगे, जिससे वे बहुत धीमी हो जाएंगे
  • export LC_ALL=Cअगर आप sortपर्यावरण की परवाह किए बिना लगातार ऑर्डर देना चाहते हैं तो सेटिंग पर भी विचार करें !
  • यदि आपको sortअपने डेटा की आवश्यकता है , तो संभवतः हर चीज की तुलना में अधिक समय (और संसाधन: सीपीयू, मेमोरी, डिस्क) लगेगा, इसलिए sortआदेशों की संख्या और उन फ़ाइलों के आकार को कम करने का प्रयास करें जिन्हें वे छांट रहे हैं।
  • एक एकल पाइपलाइन, जब संभव हो, आमतौर पर सबसे अधिक कुशल होता है - मध्यवर्ती फ़ाइलों के साथ अनुक्रम में कई पाइपलाइनों को चलाना, अधिक पठनीय और डिबग-सक्षम हो सकता है, लेकिन आपके कार्यक्रम में लगने वाले समय में वृद्धि करेगा।

6
कई सरल उपकरणों की पाइपलाइन (विशेष रूप से उल्लिखित, जैसे सिर, पूंछ, grep, सॉर्ट, कट, ट्र, sed, ...) अक्सर अनावश्यक रूप से उपयोग की जाती हैं, खासकर यदि आपके पास पहले से ही उस पाइपलाइन में एक awk उदाहरण है जो कर सकते हैं उन सरल उपकरणों के कार्यों के रूप में अच्छी तरह से। एक अन्य मुद्दा यह माना जाता है कि पाइपलाइनों में आप पाइप लाइन के सामने की ओर की प्रक्रियाओं से लेकर पीछे की तरफ दिखाई देने वाली प्रक्रियाओं तक राज्य की जानकारी को सरल और विश्वसनीय तरीके से पास नहीं कर सकते। यदि आप साधारण कार्यक्रमों की ऐसी पाइपलाइनों के लिए उपयोग करते हैं तो आपके पास एक एकल स्थान है।
Janis

14

हाँ लेकिन...

स्टीफन Chazelas का सही जवाब पर आधारित है विशिष्ट बाइनरी, जैसे के लिए हर पाठ आपरेशन सौंपने की अवधारणा grep, awk, sedऔर अन्य।

जैसा कि खुद से बहुत सी चीजें करने में सक्षम है, कांटे छोड़ने से तेज हो सकता है (यहां तक ​​कि सभी काम करने के लिए एक और दुभाषिया चलाने से भी)।

नमूने के लिए, इस पोस्ट पर एक नज़र डालें:

https://stackoverflow.com/a/38790442/1765658

तथा

https://stackoverflow.com/a/7180078/1765658

परीक्षण करें और तुलना करें ...

बेशक

उपयोगकर्ता इनपुट और सुरक्षा के बारे में कोई विचार नहीं है !

वेब एप्लिकेशन को तहत न लिखें !!

लेकिन सर्वर प्रशासन कार्य, जहां की एक बहुत कुछ के लिए के स्थान पर इस्तेमाल किया जा सकता , builtins बैश का उपयोग कर बहुत ही कुशल हो सकता है।

मेरा अर्थ:

सिस्टम के प्रशासन की तुलना में बिन बर्तनों जैसे उपकरण लिखना एक ही तरह का काम नहीं है।

तो वही लोग नहीं!

जहाँ sysadmins को जानना होता है shell, वे अपने पसंदीदा (और सबसे अच्छे ज्ञात) टूल का उपयोग करके प्रोटोटाइप लिख सकते हैं ।

यदि यह नई उपयोगिता (प्रोटोटाइप) वास्तव में उपयोगी है, तो कुछ अन्य लोग कुछ अधिक विनियोजित भाषा का उपयोग करके समर्पित उपकरण विकसित कर सकते हैं।


1
अच्छा उदाहरण। आपका दृष्टिकोण निश्चित रूप से लोलोक्स एक से अधिक कुशल है, लेकिन ध्यान दें कि टेंसिबाई का उत्तर (इस आईएमओ को करने का सही तरीका, जो शेल लूप का उपयोग किए बिना है) आपकी तुलना में तीव्रता का क्रम है। और तुम्हारा बहुत तेज है अगर तुम उपयोग नहीं करते bash। (मेरे सिस्टम पर मेरे परीक्षण में ksh93 के साथ 3 गुना से अधिक उपवास)। bashआम तौर पर सबसे धीमी खोल है। यहां तक zshकि उस स्क्रिप्ट पर दोगुना उपवास है। आप के पास कुछ समस्याएँ भी हैं जिनके बिनारक्त चर और उपयोग हैं read। इसलिए आप वास्तव में मेरे बहुत सारे बिंदुओं को यहां बता रहे हैं।
स्टीफन चेज़लस

@ स्टीफनचेज़ेलैस मैं सहमत हूं, बैश शायद सबसे धीमा शेल लोग हैं जो आज उपयोग कर सकते हैं, लेकिन वैसे भी सबसे व्यापक रूप से उपयोग किया जाता है।
एफ। हौरी

@ स्टीफनचेज़लस ने अपने उत्तर पर एक पर्ल संस्करण पोस्ट किया है
एफ। होरी

1
@Tensibai, तो आप पाएंगे POSIXsh , Awk , Sed , grep, ed, ex, cut, sort, joinबैश की तुलना में अधिक विश्वसनीयता के साथ ... सभी या पर्ल।
वाइल्डकार्ड

1
@Tensibai, U & L द्वारा संबंधित सभी प्रणालियों में से, उनमें से अधिकांश (Solaris, FreeBSD, HP / UX, AIX, अधिकांश एम्बेडेड लिनक्स सिस्टम ...) bashडिफ़ॉल्ट रूप से स्थापित नहीं हैं । bashज्यादातर पर केवल एप्पल MacOS और GNU सिस्टम (मुझे लगता है कि आप क्या कहते हैं है पाया जाता है प्रमुख वितरण ,) हालांकि कई सिस्टम भी एक वैकल्पिक पैकेज के रूप में यह है (जैसे zsh, tcl, python...)
स्टीफन Chazelas
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.