शेल स्वचालित रूप से "बिल्ली के बेकार उपयोग" को ठीक क्यों नहीं करता है? [बन्द है]


28

बहुत से लोग ऑन्लाइनर और स्क्रिप्ट्स का उपयोग करते हैं, जिनमें लाइनें होती हैं

cat "$MYFILE" | command1 | command2 > "$OUTPUT"

पहले catको अक्सर "बिल्ली का बेकार उपयोग" कहा जाता है, क्योंकि तकनीकी रूप से इसे एक नई प्रक्रिया (अक्सर /usr/bin/cat) शुरू करने की आवश्यकता होती है, जहां कमांड से होने पर इससे बचा जा सकता था।

< "$MYFILE" command1 | command2 > "$OUTPUT"

क्योंकि तब शेल को केवल शुरू करने की जरूरत है command1और बस stdinदिए गए फ़ाइल को इंगित करें ।

शेल यह रूपांतरण स्वचालित रूप से क्यों नहीं करता है? मुझे लगता है कि "बिल्ली का बेकार उपयोग" वाक्यविन्यास पढ़ना आसान है और शेल में स्वचालित रूप से बेकार बिल्ली से छुटकारा पाने के लिए पर्याप्त जानकारी होनी चाहिए। catPOSIX मानक में परिभाषित किया गया है तो खोल रास्ते में एक द्विआधारी का उपयोग करने का आंतरिक रूप से बजाय इसे लागू करने की अनुमति दी जानी चाहिए। शेल में केवल एक तर्क संस्करण के लिए कार्यान्वयन शामिल हो सकता है और पथ में द्विआधारी में वापसी हो सकती है।


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

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

3
शेल को पूरी तरह से catखुद को लागू करने की अनुमति है, हालांकि, या किसी अन्य उपयोगिता। यह जानने की भी अनुमति है कि सिस्टम के काम के अन्य उपयोगिताओं का उपयोग कैसे किया जाता है (जैसे यह जान सकता है कि सिस्टम के साथ आया बाहरी grepकार्यान्वयन कैसे व्यवहार करता है)। यह करने के लिए पूरी तरह से व्यवहार्य है, इसलिए यह आश्चर्य की पूरी तरह से उचित है कि वे क्यों नहीं करते हैं।
माइकल होमर

6
@MichaelHomer उदाहरण से यह पता चल सकता है कि सिस्टम के साथ आने वाला बाहरी grep कार्यान्वयन कैसे व्यवहार करता है इसलिए शेल के व्यवहार पर अब निर्भरता है grep। और sed। और awk। और du। और कितने सैकड़ों यदि अन्य उपयोगिताओं के हजारों नहीं हैं?
एंड्रयू हेनले

19
यह मेरे लिए अपने आदेशों को संपादित करने के लिए मेरे खोल का बहुत बड़ा हिस्सा होगा।
अज़ोर अहई

जवाबों:


25

2 कमांड समतुल्य नहीं हैं: त्रुटि से निपटने पर विचार करें:

cat <file that doesn't exist> | less एक खाली स्ट्रीम का उत्पादन करेगा जो कि पाइप किए गए प्रोग्राम को पास किया जाएगा ... जैसे कि आप कुछ नहीं दिखा रहे डिस्प्ले के साथ समाप्त होते हैं।

< <file that doesn't exist> less बार खोलने में विफल रहेगा, और फिर कम से कम न खोलें।

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


1
मैं आपकी प्रतिक्रिया को स्वीकार करूँगा क्योंकि मुझे लगता है कि यह दोनों वाक्यविन्यासों के बीच सबसे महत्वपूर्ण अंतर है। इसके साथ वाला संस्करण catहमेशा पाइपलाइन में दूसरी कमांड को निष्पादित करेगा जबकि इनपुट इनपुट पुनर्निर्देशन वाला संस्करण केवल कमांड को निष्पादित नहीं करेगा यदि इनपुट फ़ाइल गायब है।
मिकको रेंटालिनेन

हालाँकि, ध्यान दें जो <"missing-file" grep foo | echo 2निष्पादित grepनहीं करेगा लेकिन निष्पादित करेगा echo
मिकको रैंटलैनेन

51

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

catएक स्क्रिप्ट में "बेकार उपयोग" के उदाहरणों को ठीक करना स्क्रिप्ट के स्रोत कोड को मैन्युअल रूप से ठीक करने का एक मुख्य रूप से मामला है। शेलचेक जैसे उपकरण स्पष्ट मामलों को इंगित करके इसके साथ मदद कर सकते हैं:

$ cat script.sh
#!/bin/sh
cat file | cat
$ shellcheck script.sh

In script.sh line 2:
cat file | cat
    ^-- SC2002: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead.

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

खोल जरूरी नहीं जानता कि क्या catहै। यह संभवतः आपके या किसी फंक्शन में कहीं से भी कोई कमांड हो सकता है $PATH

यदि ऐसा है तो एक अंतर्निहित आदेश (जो यह कुछ गोले में हो सकता है), यह होगा पाइप लाइन के रूप में यह अपने में निर्मित के शब्दों का पता होगा पुनर्निर्माण करने की क्षमता है catआदेश। ऐसा करने से पहले, मूल रूप से, इसके बाद पाइपलाइन में अगले कमांड के बारे में धारणा बनानी होगी cat

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

यह प्रश्न समान ( बहुत सामान्य अर्थ में) " क्या कोई कंपाइलर है जो अपने आप ही सिंटैक्स त्रुटियों को ठीक करने का प्रयास करता है? " । आशय के आधार पर कोड को स्वचालित रूप से बदलने के बारे में विचार काफी हद तक समान है।


यह शेल के लिए पूरी तरह से कंफर्म है कि क्या catहै, और पाइपलाइन में अन्य कमांड, (जैसा कि अगर नियम है) और तदनुसार व्यवहार करते हैं, वे सिर्फ इसलिए यहां नहीं हैं क्योंकि यह व्यर्थ है और बहुत कठिन है।
माइकल होमर

4
@ मिचेलहोमर हां। लेकिन यह उसी नाम के फ़ंक्शन के साथ एक मानक कमांड को ओवरलोड करने की भी अनुमति देता है।
Kusalananda

2
@PhilipCouling जब तक यह ज्ञात है कि पाइप लाइन की कोई भी देखभाल नहीं करता है यह बिल्कुल अनुरूप है। शेल को विशेष रूप से उपयोगिताओं को बिल्डिंग्स या शेल फ़ंक्शन के साथ बदलने की अनुमति है और जिनके पास कोई निष्पादन पर्यावरण प्रतिबंध नहीं है, इसलिए जब तक बाहरी परिणाम अप्रत्यक्ष है तब तक इसकी अनुमति है। आपके मामले के लिए, cat /dev/ttyक्या वह दिलचस्प है जो अलग होगा<
माइकल होमर

1
@MichaelHomer जब तक बाहरी परिणाम अप्रभेद्य है, इसकी अनुमति है इसका मतलब है कि इस तरह से अनुकूलित उपयोगिताओं के पूरे सेट का व्यवहार कभी नहीं बदल सकता है । वह परम निर्भर नरक होना है।
एंड्रयू हेनले

3
@MichaelHomer जैसा कि अन्य टिप्पणियों में कहा गया है, निश्चित रूप से यह शेल के लिए पूरी तरह से अनुकूल है कि ओपी के इनपुट को देखते हुए यह बताना असंभव है कि catकमांड वास्तव में इसे निष्पादित किए बिना क्या करता है । के लिए आप सभी (और शेल) पता है, ओ पी एक आदेश है cat, उसके रास्ते में जो एक इंटरैक्टिव बिल्ली अनुकरण है "myFile" बस संग्रहीत खेल राज्य है, और command1और command2वर्तमान खेल सत्र के बारे में कुछ आंकड़े postprocessing कर रहे हैं ...
alephzero

34

क्योंकि यह बेकार नहीं है।

के मामले में cat file | cmd, एफडी 0(स्टडिन) cmdएक पाइप होगा, और इसके मामले में cmd <fileएक नियमित फ़ाइल, डिवाइस, आदि हो सकता है।

एक पाइप में एक नियमित फ़ाइल से अलग शब्दार्थ होते हैं, और इसका शब्दार्थ एक नियमित फ़ाइल का एक उपसमूह नहीं होता है:

  • एक नियमित फ़ाइल को सार्थक तरीके से select(2)एड या poll(2)एड नहीं किया जा सकता है ; इस select(2)पर वह हमेशा "तैयार" लौटेगा। epoll(2)लिनक्स पर जैसे उन्नत इंटरफेस बस नियमित फ़ाइलों के साथ काम नहीं करेंगे।

  • लिनक्स पर वहाँ सिस्टम कॉल (हैं splice(2), vmsplice(2), tee(2)) जो केवल पाइप पर काम [1]

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

[1] आप नहीं इस अवसर के लिए बना एक सरल उदाहरण चाहते हैं, आप मेरे पर Git "कार्यकारी द्विआधारी stdin से" देख सकते हैं सार टिप्पणी में कुछ स्पष्टीकरण के साथ यहाँcatUUoC के बिना इसे काम करने के लिए इसे अंदर लागू करना इसे 2 या 3 गुना बड़ा बना देगा।


2
वास्तव में, ksh93 आंतरिक रूप से कुछ बाहरी आदेशों को लागू करता हैcat
jrw32982

3
cat /dev/urandom | cpu_bound_programread()एक अलग प्रक्रिया में सिस्टम कॉल चलाता है। उदाहरण के लिए लिनक्स पर, अधिक रैंडम नंबर जेनरेट करने का वास्तविक सीपीयू काम (जब पूल खाली होता है) उस सिस्टम कॉल में किया जाता है, इसलिए एक अलग प्रक्रिया का उपयोग करके आप इनपुट के रूप में यादृच्छिक डेटा उत्पन्न करने के लिए एक अलग सीपीयू कोर का लाभ उठा सकते हैं। उदाहरण के लिए यादृच्छिक अंकों से युक्त 1 जीबी टेक्स्ट फ़ाइल उत्पन्न करने का सबसे तेज़ तरीका क्या है?
पीटर कॉर्डेस

4
अधिकांश मामलों के लिए अधिक महत्वपूर्ण बात, इसका मतलब lseekयह नहीं होगा। cat foo.mp4 | mpv -काम करेगा, लेकिन आप mpv या mplayer के कैश बफर से आगे की ओर नहीं देख सकते। लेकिन एक फ़ाइल से पुनर्निर्देशित इनपुट के साथ, आप कर सकते हैं। cat | mpv -यह जांचने का एक तरीका है कि कोई MP4 moovफ़ाइल के प्रारंभ में उसका परमाणु है, इसलिए इसे अंत और पीछे जाने के बिना खेला जा सकता है (अर्थात यदि यह स्ट्रीमिंग के लिए उपयुक्त है)। ऐसे अन्य मामलों की कल्पना करना आसान है, जहां आप किसी प्रोग्राम को गैर-खोज योग्य फ़ाइलों /dev/stdinके लिए catबनाम रीडायरेक्ट पर चलाकर परीक्षण करना चाहते हैं ।
पीटर कॉर्डेस

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

17

क्योंकि बेकार बिल्ली का पता लगाना वास्तव में कठिन है।

मेरे पास एक शेल स्क्रिप्ट थी जहां मैंने लिखा था

cat | (somecommand <<!
...
/proc/self/fd/3
...
!) 0<&3

यदि catइसे हटा दिया गया था तो शेल स्क्रिप्ट उत्पादन में विफल रही su -c 'script.sh' someuser। जाहिरा तौर पर अतिरेक के catकारण मानक इनपुट के मालिक को उपयोगकर्ता को स्क्रिप्ट में बदलाव करना पड़ा, ताकि वह फिर से /procकाम कर सके।


यह मामला बहुत आसान होगा क्योंकि यह स्पष्ट रूप से catएक पैरामीटर द्वारा पालन ​​किए गए सरल मॉडल का पालन नहीं करता है, इसलिए शेल को catअनुकूलित शॉर्टकट के बजाय वास्तविक निष्पादन योग्य का उपयोग करना चाहिए । हालांकि वास्तविक प्रक्रियाओं के लिए संभवतः अलग-अलग क्रेडेंशियल या गैर-मानक स्टड पर अच्छा बिंदु।
मिको रांटलैनन

13

tl; dr: गोले स्वचालित रूप से नहीं करते हैं क्योंकि लागत संभावित लाभों से अधिक होती है।

अन्य उत्तरों ने स्टडिन के एक पाइप होने और एक फाइल होने के बीच तकनीकी अंतर को इंगित किया है। इसे ध्यान में रखते हुए, शेल निम्न में से एक कर सकता है:

  1. बिलिन के catरूप में लागू करें , फिर भी फ़ाइल v। पाइप भेद को संरक्षित करना। यह एक निष्पादन की लागत को बचाएगा और शायद, संभवतः, एक कांटा।
  2. यदि फाइल / पाइप मायने रखती है तो यह देखने के लिए उपयोग किए जाने वाले विभिन्न कमांड के ज्ञान के साथ पाइप लाइन का पूर्ण विश्लेषण करें, फिर उस पर आधारित कार्य करें।

आगे आपको प्रत्येक दृष्टिकोण की लागतों और लाभों पर विचार करना होगा। लाभ काफी सरल हैं:

  1. किसी भी स्थिति में, निष्पादन से बचें (के cat)
  2. दूसरे मामले में, जब पुनर्निर्देशन प्रतिस्थापन संभव है, तो एक कांटा से बचा जाए।
  3. ऐसे मामलों में जहां आपको एक पाइप का उपयोग करना पड़ता है, यह कभी-कभी कांटा / vfork से बचने के लिए संभव हो सकता है, लेकिन अक्सर नहीं। ऐसा इसलिए है क्योंकि बिल्ली के समतुल्य को बाकी पाइपलाइन की तरह ही चलना होगा।

इसलिए आप थोड़ा CPU समय और मेमोरी सेव करें, खासकर यदि आप कांटे से बच सकते हैं। बेशक, आप केवल इस समय और मेमोरी को सहेजते हैं जब सुविधा वास्तव में उपयोग की जाती है। और आप केवल वास्तव में कांटा / निष्पादन समय बचा रहे हैं; बड़ी फ़ाइलों के साथ, समय ज्यादातर I / O समय होता है (यानी, डिस्क से फ़ाइल पढ़ने वाला बिल्ली)। तो आपको पूछना होगा: catशेल स्क्रिप्ट में कितनी बार (बेकार) उपयोग किया जाता है जहां प्रदर्शन वास्तव में मायने रखता है? अन्य सामान्य शेल बिल्डरों से इसकी तुलना करें test- यह कल्पना करना कठिन है cat(बेकार) यहां तक ​​कि दसवें के रूप में अक्सर testउपयोग किया जाता है जो उस मामले में उपयोग किया जाता है। यह एक अनुमान है, मैंने मापा नहीं है, जो कुछ ऐसा है जिसे आप कार्यान्वयन के किसी भी प्रयास से पहले करना चाहते हैं। (या इसी तरह, किसी और को उदाहरण के लिए लागू करने के लिए कहकर, एक सुविधा अनुरोध।)

आगे आप पूछते हैं: लागत क्या है। मन में आने वाली दो लागतें (ए) शेल में अतिरिक्त कोड हैं, जो इसके आकार को बढ़ाता है (और इस प्रकार संभवतः मेमोरी का उपयोग करता है), अधिक रखरखाव कार्य की आवश्यकता होती है, कीड़े आदि के लिए एक और स्पॉट है; और (b) बैकवर्ड कम्पैटिबिलिटी सरप्राइज़, POSIX catबहुत सारी विशेषताओं को छोड़ देता है जैसे, GNU कोरुटिल्स cat, इसलिए आपको सावधान रहना catहोगा कि बिलिन क्या लागू करेगा।

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

  2. पाइपलाइन के विश्लेषण के लिए, मुझे नहीं लगता कि गोले वर्तमान में ऐसा कुछ करते हैं (कुछ एक पाइपलाइन के अंत को पहचानते हैं और कांटे से बच सकते हैं)। अनिवार्य रूप से आप शेल में एक (आदिम) अनुकूलक जोड़ रहे होंगे; ऑप्टिमाइज़र अक्सर जटिल कोड और बहुत सारे बग का स्रोत बनते हैं। और वे कीड़े आश्चर्यचकित हो सकते हैं - शेल स्क्रिप्ट में मामूली बदलाव बग को टालने या ट्रिगर करने से हवा सकता है।

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


10

catआदेश स्वीकार कर सकते हैं -के लिए एक मार्कर के रूप stdin । ( POSIX , " यदि कोई फ़ाइल '-' है, तो बिल्ली की उपयोगिता अनुक्रम में उस बिंदु पर मानक इनपुट से पढ़ी जाएगी। ") यह एक फ़ाइल या स्टड की सरल हैंडलिंग की अनुमति देता है जहां अन्यथा यह अस्वीकृत हो जाएगा।

इन दो तुच्छ विकल्पों पर विचार करें, जहां शेल तर्क $1है -:

cat "$1" | nl    # Works completely transparently
nl < "$1"        # Fails with 'bash: -: No such file or directory'

एक और समय catउपयोगी है, जहां इसे जानबूझकर एक गैर-ऑप के रूप में उपयोग किया जाता है, केवल शेल सिंटैक्स बनाए रखने के लिए:

file="$1"
reader=cat
[[ $file =~ \.gz$ ]] && reader=zcat
[[ $file =~ \.bz2$ ]] && reader=bzcat
"$reader" "$file"

अंत में, मुझे विश्वास है कि यूयूओसी को वास्तव में सही ढंग से बाहर बुलाया जा सकता है जब catएक फ़ाइलनाम के साथ प्रयोग किया जाता है जिसे एक नियमित फ़ाइल के रूप में जाना जाता है (यानी डिवाइस या पाइप का नाम नहीं), और यह कि कमांड को कोई झंडे नहीं दिए गए हैं:

cat file.txt

किसी भी अन्य स्थिति में catस्वयं की परोपकारिता की आवश्यकता हो सकती है।


6

बिल्ली कमांड उन चीजों को कर सकती है जो शेल आवश्यक रूप से नहीं कर सकते हैं (या कम से कम, आसानी से नहीं कर सकते हैं)। उदाहरण के लिए, मान लें कि आप उन वर्णों को प्रिंट करना चाहते हैं जो अन्यथा अदृश्य हो सकते हैं, जैसे टैब, कैरिज रिटर्न, या न्यूलाइन्स। वहाँ केवल शेल शेलिन कमांड के साथ ऐसा करने का एक तरीका हो सकता है, लेकिन मैं अपने सिर के ऊपर से कोई भी नहीं सोच सकता। बिल्ली का GNU संस्करण -Aतर्क या तर्क के साथ ऐसा कर सकता है -v -E -T(मुझे बिल्ली के अन्य संस्करणों के बारे में पता नहीं है, हालांकि)। आप प्रत्येक पंक्ति को एक पंक्ति संख्या के साथ उपसर्ग भी कर सकते हैं -n(फिर से, IDK यदि गैर-GNU संस्करण ऐसा कर सकते हैं)।

बिल्ली का एक और फायदा यह है कि यह आसानी से कई फाइलों को पढ़ सकती है। ऐसा करने के लिए, कोई बस टाइप कर सकता है cat file1 file2 file3। एक शेल के साथ भी ऐसा करने के लिए, चीजें मुश्किल हो जाएंगी, हालांकि एक सावधानी से तैयार की गई लूप सबसे अधिक समान परिणाम प्राप्त कर सकती है। उस ने कहा, क्या आप वास्तव में ऐसा लूप लिखने के लिए समय निकालना चाहते हैं, जब इस तरह का एक सरल विकल्प मौजूद हो? मैं नही!

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

बिल्ली कमांड भी ऐसे उदाहरणों में मानक इनपुट स्वीकार करने के लिए एक कमांड को मजबूर करने के लिए उपयोगी हो सकता है जो यह नहीं हो सकता है। निम्नलिखित को धयान मे रखते हुए:

echo 8 | sleep

संख्या "8" को "नींद" कमांड द्वारा स्वीकार नहीं किया जाएगा, क्योंकि यह वास्तव में मानक इनपुट को स्वीकार करने के लिए कभी नहीं था। इस प्रकार, नींद उस इनपुट की उपेक्षा करेगी, तर्कों की कमी के बारे में शिकायत करेगी, और बाहर निकल जाएगी। हालांकि, अगर एक प्रकार:

echo 8 | sleep $(cat)

कई गोले इसका विस्तार करेंगे sleep 8, और बाहर निकलने से पहले नींद 8 सेकंड तक इंतजार करेगी। आप ssh के साथ भी कुछ ऐसा कर सकते हैं:

command | ssh 1.2.3.4 'cat >> example-file'

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

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


मैं अंतिम वाक्य को "आसानी से संभव नहीं है" समाप्त कर
दूंगा

3

याद रखें कि एक उपयोगकर्ता catअपने में हो सकता है $PATHजो कि POSIX नहीं है cat(लेकिन शायद कुछ संस्करण जो कुछ लॉग कर सकते हैं)। उस स्थिति में, आप इसे हटाने के लिए शेल नहीं चाहते हैं।

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

इसके अलावा, व्यवहार में, cat एक बहुत तेज कार्यक्रम है। इससे बचने के कुछ व्यावहारिक कारण (सौंदर्यशास्त्र को छोड़कर) हैं।

FOSDEM2018 में Yann Regis-Gianas द्वारा उत्कृष्ट Parsing POSIX [s] नरक वार्ता भी देखें । यह अन्य अच्छे कारण देता है जो आप एक खोल में सपने देखने के प्रयास से बचने के लिए करते हैं।

यदि प्रदर्शन वास्तव में गोले के लिए एक मुद्दा था, तो किसी ने एक ऐसे शेल का प्रस्ताव किया होगा जो परिष्कृत पूरे कार्यक्रम संकलक अनुकूलन, स्थिर स्रोत कोड विश्लेषण और सिर्फ-इन-टाइम संकलन तकनीकों का उपयोग करता है (इन तीनों डोमेन में दशकों की प्रगति और वैज्ञानिक प्रकाशन हैं और समर्पित हैं सम्मेलनों, के तहत जैसे SIGPLAN )। अफसोस की बात है, यहां तक ​​कि एक दिलचस्प शोध विषय के रूप में, जो वर्तमान में अनुसंधान एजेंसियों या उद्यम पूंजीपतियों द्वारा वित्त पोषित नहीं है, और मैं यह कह रहा हूं कि यह केवल प्रयास के लायक नहीं है। दूसरे शब्दों में, संभवतः शेल के अनुकूलन के लिए कोई महत्वपूर्ण बाजार नहीं है । यदि आपके पास इस तरह के अनुसंधान पर खर्च करने के लिए आधा मिलियन यूरो हैं, तो आप आसानी से किसी को ऐसा करने के लिए पाएंगे, और मुझे विश्वास है कि यह सार्थक परिणाम देगा।

एक व्यावहारिक पक्ष पर, अपने प्रदर्शन को बेहतर बनाने के लिए, किसी भी बेहतर स्क्रिप्टिंग भाषा (पायथन, एडब्ल्यूके, गुइल, ...) में एक छोटी (अन सौ लाइनों) शेल स्क्रिप्ट को बेहतर बनाने के लिए किया जाता है। और बड़ी शेल स्क्रिप्ट लिखने के लिए यह उचित नहीं है (कई सॉफ्टवेयर इंजीनियरिंग कारणों के लिए): जब आप एक शेल स्क्रिप्ट लिख रहे हैं, जो सौ लाइनों से अधिक है, तो आपको इसे कुछ और उपयुक्त भाषा में लिखने (यहां तक ​​कि पठनीयता और रखरखाव के कारणों के लिए) पर विचार करने की आवश्यकता है। : एक प्रोग्रामिंग भाषा के रूप में शेल बहुत खराब है। हालाँकि, कई बड़ी जनरेट की गई शेल स्क्रिप्ट हैं, और अच्छे कारणों के लिए (जैसे GNU ऑटोकॉनफ़ उत्पन्न configureस्क्रिप्ट)।

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


3
"इससे बचने के लिए कुछ व्यावहारिक कारण" - जो कोई भी cat some-huge-log | tail -n 5दौड़ने के लिए इंतजार कर रहा है (जहां tail -n 5 some-huge-logसीधे अंत तक कूद सकता है, जबकि catकेवल आगे-पीछे पढ़ता है) असहमत होगा।
चार्ल्स डॉफी

टिप्पणी की जाँच करें ^ catदसियों जीबी रेंज में एक बड़ी पाठ फ़ाइल आईएनजी (जो परीक्षण के लिए बनाई गई थी) थोड़े लंबे समय लेती है। सिफारिश नहीं करेंगे।
सर्गी कोलोडियाज़नी

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

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

2

@ कुसलानंद का जवाब (और @alephzero टिप्पणी) जोड़ना, बिल्ली कुछ भी हो सकती है:

alias cat='gcc -c'
cat "$MYFILE" | command1 | command2 > "$OUTPUT"

या

echo 'echo 1' > /usr/bin/cat
cat "$MYFILE" | command1 | command2 > "$OUTPUT"

कोई कारण नहीं है कि सिस्टम पर बिल्ली (अपने दम पर) या / usr / बिन / बिल्ली वास्तव में बिल्ली का बच्चा उपकरण है।


3
catPOSIX द्वारा परिभाषित व्यवहार के अलावा अन्य भी बेतहाशा भिन्न नहीं होना चाहिए।
रोजा

2
@roaima: PATH=/home/Joshua/bin:$PATH cat ...क्या आप सुनिश्चित हैं कि आप जानते हैं कि catअब क्या होता है?
जोशुआ

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

@ जोशुआ: अधिकांश प्लेटफार्मों पर, गोले जानते हैं (या पता कर सकते हैं) कि कौन सी निर्देशिका पीएसआईएक्स कमांड को लागू करने वाले निष्पादन योग्य हैं। तो आप बस उर्फ ​​विस्तार और पथ संकल्प के बाद तक प्रतिस्थापन को स्थगित कर सकते हैं, और केवल इसके लिए करते हैं /bin/cat। (और आप इसे एक ऐसा विकल्प बना सकते हैं जिसे आप बंद कर सकते हैं।) या आप catएक शेल-इन (जो शायद /bin/catकई आर्गन्स के लिए वापस गिर जाता है ?) बनाएंगे, ताकि उपयोगकर्ता यह नियंत्रित कर सकें कि उन्हें बाहरी संस्करण सामान्य चाहिए या नहीं? रास्ता, साथ enable cat। के लिए पसंद है kill। (मैं सोच रहा था कि बैश command catकाम करेगा, लेकिन यह बिल्डिन्स को नहीं छोड़ता)
पीटर कॉर्ड्स

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

1

बिल्ली के लिए दो "बेकार" उपयोग करता है:

sort file.txt | cat header.txt - footer.txt | less

... यहाँ catफ़ाइल और पाइप इनपुट को मिलाने के लिए उपयोग किया जाता है।

find . -name '*.info' -type f | sh -c 'xargs cat' | sort

... यहाँ xargsएक लगभग अनंत संख्या में फिल्नामें स्वीकार किए जा सकते हैं और catजितनी बार जरूरत हो उतनी बार चलाएं जबकि यह सब एक धारा की तरह व्यवहार करता है। तो यह बड़ी फ़ाइल सूचियों के लिए काम करता है जहाँ प्रत्यक्ष उपयोग xargs sortनहीं होता है।


इन दोनों उपयोग के मामलों को तुच्छ रूप से खोलकर बनाया जाएगा ताकि केवल catएक ही तर्क के साथ चरणबद्ध तरीके से कॉल किया जा सके। विशेष रूप से मामला जहां shएक स्ट्रिंग को पारित किया गया है और सीधे xargsकॉल करेगा catवहाँ कोई रास्ता नहीं है कि शेल का उपयोग कर सकता है यह अंतर्निहित कार्यान्वयन है।
मिकको रेंटालिनेन

0

अन्य चीजों के अलावा, cat-चेक अतिरिक्त प्रदर्शन ओवरहेड और भ्रम को जोड़ देगा , जिसका उपयोग catवास्तव में बेकार है, IMHO, क्योंकि ऐसे चेक अक्षम हो सकते हैं और वैध catउपयोग के साथ समस्याएं पैदा कर सकते हैं ।

जब कमांड मानक धाराओं के साथ व्यवहार करते हैं, तो उन्हें केवल मानक फ़ाइल विवरणकों को पढ़ने / लिखने के बारे में ध्यान रखना होगा। कमांड जान सकते हैं कि स्टड खोजी / लेसेकेबल है या नहीं, जो पाइप या फाइल को इंगित करता है।

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

(find /proc -type l | xargs ls -l | fgrep 'pipe:[20043922]') 2>/dev/null

जैसा कि लिंक में दिखाया गया है। यह 3 अधिक कमांड (इसलिए अतिरिक्त fork()एस और exec()एस) और पुनरावर्ती ट्रैवर्सल्स (इतने सारे readdir()कॉल) हैं।

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

# adding header and footer to file
( cmd; cat file; cmd ) | cmd
# tr command does not accept files as arguments
cat log1 log2 log3 | tr '[:upper:]' '[:lower:]'

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

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