क्या मुझे अनावश्यक बिल्लियों की परवाह करनी चाहिए?


50

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

तुलना

sed s/bla/blaha/ data \
| grep blah \
| grep -n babla

तथा

cat data \
| sed s/bla/blaha/ \
| grep blah \
| grep -n babla

क्या बाद का तरीका कम कुशल है? यदि हां, तो क्या अंतर इतना है कि अगर स्क्रिप्ट को चलाया जाता है, तो कहें, एक बार एक सेकंड? पठनीयता में अंतर बहुत बड़ा नहीं है।


30
मैं अपना समय इस साइट पर बेकार बिल्ली के उपयोग के बारे में लोगों को एक दूसरे पर हमला करते हुए देखने में बिताता हूं, क्योंकि मेरी प्रणाली वास्तव में बिल्ली की प्रक्रिया शुरू कर रही है
माइकल Mrozek

4
@ मिचेल: 100% सहमत हैं। बिल्ली ने मुझे पुराने usenet अवार्ड से लिंक करने में अधिक समय लिया क्योंकि मेरा कंप्यूटर कभी भी तात्कालिक रूप से बर्बाद कर देगा cat। हालाँकि मुझे लगता है कि यहाँ बड़ा प्रश्न कोड पठनीयता है जो अक्सर प्रदर्शन पर प्राथमिकता होती है । जब तेजी से वास्तव में सुंदर लिखा जा सकता है , तो क्यों नहीं? इस मुद्दे की ओर इशारा करते हुए catआमतौर पर उपयोगकर्ता को पाइपलाइन और प्रक्रियाओं की बेहतर समझ होती है। यह प्रयास के लायक है इसलिए वे अगली बार के आसपास समझदार कोड लिखते हैं।
कालेब

3
मेरे पास वास्तव में एक और कारण है जो मुझे पहले रूप में पसंद नहीं है - यदि आप पाइपलाइन की शुरुआत में एक और कमांड जोड़ना चाहते हैं , तो आपको तर्क को भी स्थानांतरित करना होगा, इसलिए संपादन अधिक कष्टप्रद है। (बेशक, इसका मतलब यह नहीं है कि आपको उपयोग करना है cat; कार्यों और पुनर्निर्देशन का उपयोग करने के बारे में कालेब की बात और साथ ही हल करती है।)
Cascabel


1
काम पर शाम हो गई है, मेरे काम करने से इनकार कर दिया गया है। मैं स्टैकओवरफ़्लो को खोलता हूं और एक प्रश्न ढूंढता हूं, जिसका शीर्षक है "क्या मुझे अनावश्यक बिल्लियों की परवाह करनी चाहिए?" और कुछ बेघर जानवरों और एक प्रोग्रामर को देखें, उन्हें खिलाने या न खाने के बारे में विचार करना ...
बोरिस बुर्कोव

जवाबों:


46

"निश्चित" उत्तर बेशक आपके लिए द यूसलेस यूज़ ऑफ़ catअवार्ड द्वारा लाया गया है ।

बिल्ली का उद्देश्य फाइलों को समेटना (या "कैटेनट") करना है। यदि यह केवल एक फ़ाइल है, तो इसे बिना किसी चीज़ के साथ समाप्‍त करना समय की बर्बादी है, और आपको एक प्रक्रिया में खर्च करना है।

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

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

यहां तक ​​कि आप इसे लिखने के साथ रचनात्मक भी प्राप्त कर सकते हैं। आम तौर पर इसे इस तरह से किसी भी आउटपुट रीडायरेक्ट या पाइप को निर्दिष्ट करने से पहले एक कमांड के अंत में रखा जाएगा:

sed s/blah/blaha/ < data | pipe

लेकिन यह इस तरह से नहीं है। यह पहले भी आ सकता है। उदाहरण के लिए आपका उदाहरण कोड इस तरह लिखा जा सकता है:

< data \
    sed s/bla/blaha/ |
    grep blah |
    grep -n babla

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

function fix_blahs () {
    sed s/bla/blaha/ |
    grep blah |
    grep -n babla
}

fix_blahs < data

आप तब जारी रख सकते हैं fix_blahs < data | fix_frogs | reorder | format_for_sql। इस तरह से पढ़ी जाने वाली एक अनुगामी वास्तव में पालन करना आसान है, और व्यक्तिगत घटकों को उनके संबंधित कार्यों में आसानी से डिबग किया जा सकता है।


26
मुझे नहीं पता था कि <fileकमांड से पहले आ सकता है। यह मेरी सभी समस्याओं को हल करता है!

3
@ टिम: बैश और जेड दोनों का समर्थन है, हालांकि मुझे लगता है कि यह बदसूरत है। जब मैं अपने कोड के बारे में चिंतित होता हूं तो सुंदर और बनाए रखने योग्य होता है, आमतौर पर मैं इसे साफ करने के लिए फ़ंक्शन का उपयोग करता हूं। मेरा अंतिम संपादन देखें।
कालेब

8
@ टीम <fileकमांड लाइन पर कहीं भी आ सकता है: <file grep needleया grep <file needleया grep needle <file। अपवाद जटिल आदेश हैं जैसे लूप और समूह; वहाँ समापन done/ }/ )/ आदि के बाद पुनर्निर्देशन आना चाहिए । @ कालेब यह सभी बॉर्न / पोसिक्स गोले में है। और मैं असहमत हूं कि यह बदसूरत है।
गिल्स एसओ- बुराई को रोकें '

9
@ गिल्स, बाश में आप के $(cat /some/file)साथ बदल सकते हैं $(< /some/file), जो एक ही काम करता है लेकिन एक प्रक्रिया को जन्म देने से बचता है।
cjm

3
बस यह पुष्टि करने के लिए कि $(< /some/file)सीमित पोर्टेबिलिटी है। यह बाश में काम करता है, लेकिन बिजीबॉक्स ऐश नहीं, उदाहरण के लिए, या फ्रीबीएसडी श। संभवतः डैश में काम नहीं करता है, क्योंकि पिछले तीन गोले सभी करीबी चचेरे भाई हैं।
dubiousjim

22

यहाँ कुछ कमियों का सारांश दिया गया है:

cat $file | cmd

ऊपर

< $file cmd
  • सबसे पहले, एक नोट: (चर्चा के उद्देश्य के लिए जानबूझकर) $fileऊपर के आसपास दोहरे उद्धरण गायब हैं। के मामले में cat, यह हमेशा के लिए छोड़कर एक समस्या है zsh; पुनर्निर्देशन के मामले में, यह केवल ( bashया ksh88लिपियों में नहीं) इंटरैक्टिव होने पर कुछ अन्य गोले के लिए या के लिए एक समस्या है ।
  • सबसे अधिक बार उद्धृत दोष अतिरिक्त प्रक्रिया को जन्म दिया जा रहा है। ध्यान दें कि यदि cmdबिल्ट है, तो कुछ गोले में भी 2 प्रक्रियाएं हैं bash
  • अभी भी प्रदर्शन के मोर्चे पर, शेल के अलावा जहां catबिल्ट है, वह भी एक अतिरिक्त कमांड को निष्पादित किया जा रहा है (और निश्चित रूप से लोड किया गया है, और इनिशियलाइज़ किया गया है (और यह जिस लाइब्रेरी से जुड़ा है))।
  • अभी भी प्रदर्शन के मोर्चे पर, बड़ी फ़ाइलों के लिए, इसका मतलब है कि सिस्टम को वैकल्पिक रूप से catऔर cmdप्रक्रियाओं को शेड्यूल करना होगा और पाइप बफर को लगातार भरना और खाली करना होगा। यहां तक कि अगर cmdकरता है 1GBबड़े read()प्रणाली एक समय में कहता है, नियंत्रण के बीच आगे पीछे जाना होगा catऔर cmdक्योंकि एक पाइप एक समय में डेटा के कुछ किलोबाइट से ज्यादा रोक नहीं सकते।
  • कुछ cmdएस (जैसे wc -c) कुछ अनुकूलन कर सकते हैं जब उनकी स्टड एक नियमित फ़ाइल होती है जो वे नहीं कर सकते हैं cat | cmdक्योंकि उनके स्टड सिर्फ एक पाइप है। साथ catऔर एक पाइप, यह भी मतलब है कि वे नहीं कर सकते हैं seek()फ़ाइल के भीतर। आदेशों की तरह tacया tail, कि प्रदर्शन में एक बड़ा अंतर पड़ता है इसका मतलब है कि catउनके साथ पूरे इनपुट को मेमोरी में स्टोर करने की आवश्यकता है।
  • cat $fileऔर यहां तक कि अपने अधिक सही संस्करण cat -- "$file"की तरह कुछ विशिष्ट फ़ाइल के नाम के लिए ठीक से काम नहीं करेगा -(या --helpया के साथ शुरू कुछ भी -करता है, तो आप भूल जाते हैं --)। यदि कोई उपयोग करने पर जोर देता है cat, तो उसे cat < "$file" | cmdविश्वसनीयता के लिए संभवतः उपयोग करना चाहिए ।
  • यदि $fileपढ़ने के लिए खुला नहीं हो सकता है (पहुंच से वंचित, मौजूद नहीं है ...), < "$file" cmdएक सुसंगत त्रुटि संदेश (शेल द्वारा) रिपोर्ट करेगा , और नहीं चलेगा cmd, जबकि cat $file | cmdअभी भी चलेगा, cmdलेकिन इसकी स्टड के साथ ऐसा लग रहा है जैसे यह एक खाली फ़ाइल है। इसका मतलब यह भी है कि अगर नहीं खोला जा सकता है < file cmd > file2, तो चीजों को पसंद नहीं किया जाता है।file2file

2
प्रदर्शन के बारे में: यह परीक्षण दिखाता है कि अंतर 1 pct के क्रम में है जब तक आप स्ट्रीम पर बहुत कम प्रसंस्करण नहीं कर रहे हैं oletange.blogspot.dk/2013/10/useless-use-of-cat.html
Ole Tange

2
@OleTange। यहाँ एक और परीक्षण है: truncate -s10G a; time wc -c < a; time cat a | wc -c; time cat a | cat | wc -c। बहुत सारे पैरामीटर हैं जो तस्वीर में आते हैं। प्रदर्शन जुर्माना 0 से 100% तक जा सकता है। किसी भी मामले में, मुझे नहीं लगता कि जुर्माना नकारात्मक हो सकता है।
स्टीफन चेज़लस

2
wc -cएक बहुत ही अनोखा मामला है, क्योंकि इसका एक शॉर्टकट है। यदि आप इसके बजाय करते हैं wc -wतो यह grepमेरे उदाहरण में तुलनात्मक है (यानी बहुत कम प्रसंस्करण - जो कि ऐसी स्थिति है जहां '<' फर्क कर सकता है)।
ओले तांगे

@ ओलेटेन्गे, यहां तक ​​कि ( wc -wसी 1 लोकेल में सी 1 लोकेल पर लिनक्स पर 4.9 एएमडी 64) तो मुझे लगता है कि बिल्ली का दृष्टिकोण 23% अधिक समय लेता है जब एक मल्टीकोर सिस्टम पर और 5% उन्हें एक कोर से बांधते समय। एक से अधिक कोर द्वारा एक्सेस किए गए डेटा द्वारा किए गए अतिरिक्त ओवरहेड को दिखाना। यदि आप पाइप के आकार को बदलते हैं, तो आप अलग-अलग परिणाम प्राप्त करेंगे, अलग-अलग डेटा का उपयोग करेंगे, जिसमें वास्तविक I / O एक बिल्ली के कार्यान्वयन का उपयोग करेंगे जो ब्याह का उपयोग करता है () ... सभी पुष्टि करते हैं कि चित्र में बहुत सारे पैरामीटर हैं और किसी भी मामले में catमदद नहीं करेगा।
स्टीफन चेजलस

1
मेरे लिए 1GB फ़ाइल के साथ wc -wयह लगभग 2% का अंतर है ... 15% अंतर है अगर यह सीधे सरल grep में है। फिर, अजीब तरह से, अगर यह एक एनएफएस फ़ाइल शेयर पर है, तो यह वास्तव में 20% तेजी से इसे पढ़ने के लिए है अगर पाइप से cat( gist.github.com/rdp/7162414833becbee5919cda855f1cb86 ) अजीब ...
rogerdpack

16

लाना <fileएक पाइप लाइन के अंत पर होने से कम पढ़ी जा सकती है cat fileशुरू में। प्राकृतिक अंग्रेजी बाएं से दाएं पढ़ती है।

लाना <fileएक पाइप लाइन के शुरू होने से भी बिल्ली की तुलना में कम पढ़ी जा सकती है, मैं कहूंगा कि। एक शब्द एक प्रतीक से अधिक पठनीय है, विशेष रूप से एक प्रतीक जो गलत तरीके से इंगित करता है।

का उपयोग करते हुए catबरकरार रखता है command | command | commandप्रारूप।


मैं सहमत हूं, <एक बार कोड का उपयोग करने से कोड कम पठनीय हो जाता है, क्योंकि यह एक मल्टीप्लिन की वाक्यविन्यास संगतता को नष्ट कर देता है।
ए.निस्क्यूस्की

@ जिम आप <इस तरह से एक उपनाम बनाकर पठनीयता को हल कर सकते हैं : alias load='<'और फिर उदाहरण के लिए उपयोग करें load file | sed ...। चलने के बाद स्क्रिप्ट का उपयोग स्क्रिप्ट में किया जा सकता है shopt -s expand_aliases
nieani

1
हाँ मुझे उपनामों के बारे में पता है। हालाँकि, यद्यपि यह उपनाम किसी शब्द के साथ प्रतीक को प्रतिस्थापित करता है, लेकिन इसके लिए पाठक को आपकी व्यक्तिगत उपनाम सेटिंग के बारे में जानना आवश्यक है, इसलिए यह बहुत पोर्टेबल नहीं है।
जिम

8

एक बात जो यहाँ के दूसरे उत्तरों से नहीं लगती है, वह catयह है कि इस तरह का उपयोग करना इस अर्थ में "बेकार" नहीं है कि "एक विलुप्त होती बिल्ली प्रक्रिया को जन्म दिया जाता है जो कोई काम नहीं करता है"; यह इस अर्थ में बेकार है कि "एक बिल्ली प्रक्रिया को जन्म दिया जाता है जो केवल अनावश्यक काम करता है"।

इन दोनों के मामले में:

sed 's/foo/bar/' somefile
<somefile sed 's/foo/bar/'

शेल एक सीड प्रक्रिया शुरू करता है जो कुछफाइल या स्टड (क्रमशः) से पढ़ता है और फिर कुछ प्रसंस्करण करता है - यह तब तक पढ़ता है जब तक कि यह एक नई रेखा को हिट नहीं करता है, पहले 'फू' (यदि कोई हो) को उस लाइन पर 'बार' से बदल देता है, तो प्रिंट करता है कि लाइन stdout और छोरों के लिए।

के मामले में:

cat somefile | sed 's/foo/bar/'

शेल एक बिल्ली की प्रक्रिया और एक sed प्रक्रिया को जन्म देता है, और बिल्ली के स्टडआउट को sed की स्टड के लिए तार करता है। बिल्ली प्रक्रिया कई किलो पढ़ती है- या शायद मेगा-बाइट फ़ाइल से बाहर निकलती है, फिर लिखती है कि अपने स्टडआउट के लिए, जहां सेड सोमंड ऊपर से दूसरे उदाहरण के रूप में वहाँ से उठाता है। जबकि सेड उस चंक को प्रोसेस कर रहा है, बिल्ली एक और चंक को पढ़ रही है और इसे अगले काम करने के लिए अपने स्टडआउट के लिए लिख रही है।

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


2
अतिरिक्त का उपयोग करने के ओवरहेड के परीक्षण के लिए oletange.blogspot.dk/2013/10/useless-use-of-cat.html देखें cat
ओले तांगे

@OleTange: मैं बस इस पर ठोकर खाई, और आपके ब्लॉग पर गया। (१) जबकि मैं अंग्रेजी में सामग्री (ज्यादातर) देखता हूं, तो मुझे इसमें शब्दों का एक समूह दिखाई देता है (मुझे लगता है) डेनिश: "क्लास्सिक", "फ्लिपकार्ड", "मैगसिन", "मोसिक", "साइडबज्लके," Øjebliksbillede " , "Tidsskyder", "Blog-arkiv", "Om Mig", "Skrevet", और "Vis kommentarer" (लेकिन "Tweet", "Like" और कुकीज़ बैनर अंग्रेजी में हैं)। क्या आप इसके बारे में जानते हैं, और क्या यह आपके नियंत्रण में है? (2) मुझे आपके टेबल (2a) को पढ़ने में परेशानी है क्योंकि ग्रिडलाइन अधूरी है, और (2 बी) मुझे समझ नहीं आ रहा है कि आप "डिफ (pct)" से क्या मतलब है।
जी-मैन का कहना है 'मोनिका'

blogspot.dk Google द्वारा चलाया जाता है। Blogspot.com से बदलने का प्रयास करें। "Diff (पीसीटी)" एमएस के साथ है catबिना एमएस से विभाजित catप्रतिशत में (उदाहरण के लिए 264 एमएस / 216 एमएस = 1.22 = 122% = 22% के साथ धीमी cat)
ओले Tange
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.