"बिल्ली फ़ाइल" के बीच अंतर क्या है? ./binary ”और“ ./binary <file ”?


102

मेरे पास एक बाइनरी है (जिसे मैं संशोधित नहीं कर सकता) और मैं कर सकता हूं:

./binary < file

मैं भी कर सकता हूँ:

./binary << EOF
> "line 1 of file"
> "line 2 of file"
...
> "last line of file"
> EOF

परंतु

cat file | ./binary

मुझे एक त्रुटि देता है। मुझे नहीं पता कि यह एक पाइप के साथ काम क्यों नहीं करता है। सभी 3 मामलों में फ़ाइल की सामग्री को बाइनरी के मानक इनपुट के लिए दिया जाता है (विभिन्न तरीकों से):

  1. bash फाइल को पढ़ता है और इसे बाइनरी के स्टिन में देता है
  2. bash स्टड से लाइनें पढ़ता है (EOF तक) और इसे बाइनरी के स्टिन को देता है
  3. बिल्ली पढ़ती है और फ़ाइल की पंक्तियों को स्टडआउट में डालती है, बैश करती है और उन्हें बाइनरी की स्टड पर पुनर्निर्देशित करती है

बाइनरी को उन 3 के बीच अंतर पर ध्यान नहीं देना चाहिए जहां तक ​​मैंने इसे समझा था। क्या कोई समझा सकता है कि तीसरा मामला काम क्यों नहीं करता है?

BTW: बाइनरी द्वारा दी गई त्रुटि है:

20170116 / 125624.689 - U3000011 स्क्रिप्ट फ़ाइल '', त्रुटि कोड '14' नहीं पढ़ सका।

लेकिन मेरा मुख्य प्रश्न यह है कि किसी भी प्रोग्राम के लिए उस 3 विकल्पों के साथ अंतर कैसे है ।

यहाँ कुछ और विवरण हैं: मैं इसे फिर से कोशिश की साथ strace और कुछ त्रुटियों वास्तव में वहाँ थे ESPIPE (अवैध तलाश) से lseek के बाद EFAULT (बुरा पता) से पढ़ा ही सही त्रुटि संदेश से पहले।

बाइनरी मैंने एक रूबी स्क्रिप्ट के साथ नियंत्रित करने की कोशिश की (अस्थायी फ़ाइलों का उपयोग किए बिना) ऑटोमैटिक (यूसी 4) से कैलापी का हिस्सा है ।


25
कूल, आपके बाइनरी में यूयूओसी डिटेक्टर एम्बेडेड है। मुझे यह चाहिेए।
xhienne

4
क्या ओएस है (इसलिए हम बता सकते हैं कि 14 क्या है अगर यह एक गलत मतलब है)?
स्टीफन चेजलस

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

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

3
@xhienne नहीं, इसमें एक प्रस्तोता catहै। ऐसा प्रतीत होता है कि आप इसका उपयोग दो फ़ाइलों को संयोजित करने के लिए नहीं कर सकते, जैसा कि इच्छित उपयोग है।
jpmc26

जवाबों:


150

में

./binary < file

binaryस्टड फ़ाइल केवल-पढ़ने के लिए मोड में खुला है। ध्यान दें कि bashफ़ाइल को बिल्कुल भी नहीं पढ़ता है, यह इसे केवल उस प्रक्रिया के फ़ाइल डिस्क्रिप्टर 0 (स्टडिन) पर पढ़ने के लिए खोलता है, जिसमें यह निष्पादित होता binaryहै।

में:

./binary << EOF
test
EOF

शेल के आधार पर binary, स्टड या तो हटाए गए अस्थायी फ़ाइल (AT & T ksh, zsh, bash ...) होगा, जिसमें test\nशेल या पाइप के रीडिंग एंड ( dash, yashऔर; शेल test\nसमानांतर में लिखते हैं) के रूप में शामिल हैं। पाइप के दूसरे छोर पर)। आपके मामले में, यदि आप उपयोग कर रहे हैं, तो bashयह एक अस्थायी फ़ाइल होगी।

में:

cat file | ./binary

शेल के आधार पर, binaryस्टड या तो पाइप का रीडिंग एंड होगा, या सॉकेट पेयर का एक सिरा जहां लेखन दिशा को बंद किया गया है (ksh93) और दूसरे छोर पर catकंटेंट लिख रहा है file

जब स्टड एक नियमित फ़ाइल (अस्थायी या नहीं) होती है, तो यह खोजी होती है। binaryशुरुआत या अंत में जा सकते हैं, रिवाइंड कर सकते हैं, आदि। यह इसे mmap भी कर सकता है, कुछ ioctl()sFIEMAP / FIBMAP की तरह (यदि <>इसके बजाय का उपयोग कर रहा है <, तो यह इसमें छिद्र / पंच छेद कर सकता है, आदि)।

दूसरी तरफ पाइप और सॉकेट जोड़े एक अंतर-प्रक्रिया संचार साधन हैं, डेटा के binaryपास बहुत कुछ नहीं कर सकता है read(हालांकि कुछ पाइप-विशिष्ट ioctl()s जैसे कुछ ऑपरेशन भी हैं जो यह उन पर कर सकता है और नियमित फ़ाइलों पर नहीं) ।

अधिकांश समय, यह याद आ रही क्षमता के लिए है seekकि विफल अनुप्रयोगों का कारण बनता है / जब पाइप के साथ काम करने की शिकायत है, लेकिन यह अन्य सिस्टम कॉल कि नियमित रूप से फाइलों पर मान्य लेकिन फ़ाइलों के विभिन्न प्रकार पर नहीं कर रहे हैं के किसी भी हो सकता है (जैसे mmap(), ftruncate(), fallocate()) । लिनक्स पर, व्यवहार में एक बड़ा अंतर होता है जब आप खोलते हैं /dev/stdinजबकि fd 0 एक पाइप पर या एक नियमित फ़ाइल पर होता है।

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

$ unzip -l file.zip
Archive:  file.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
       11  2016-12-21 14:43   file
---------                     -------
       11                     1 file
$ unzip -l <(cat file.zip)
     # more or less the same as cat file.zip | unzip -l /dev/stdin
Archive:  /proc/self/fd/11
  End-of-central-directory signature not found.  Either this file is not
  a zipfile, or it constitutes one disk of a multi-part archive.  In the
  latter case the central directory and zipfile comment will be found on
  the last disk(s) of this archive.
unzip:  cannot find zipfile directory in one of /proc/self/fd/11 or
        /proc/self/fd/11.zip, and cannot find /proc/self/fd/11.ZIP, period.

unzipफ़ाइल के अंत में संग्रहीत सूचकांक को पढ़ने की जरूरत है, और फिर संग्रह के सदस्यों को पढ़ने के लिए फ़ाइल के भीतर की तलाश करें। लेकिन यहाँ, फ़ाइल (नियमित रूप से पहले मामले में, दूसरे में पाइप) को एक पथ तर्क के रूप में दिया जाता है unzip, और unzipइसे स्वयं (आमतौर पर fd पर अन्य को 0 पर खोलता है) बजाय माता-पिता द्वारा पहले से खोले गए fd को प्राप्त करने के बजाय। यह अपने स्टड से ज़िप फ़ाइलों को नहीं पढ़ता है। स्टड ज्यादातर उपयोगकर्ता बातचीत के लिए उपयोग किया जाता है।

यदि आप binaryएक टर्मिनल एमुलेटर में चल रहे इंटरएक्टिव शेल के संकेत पर पुनर्निर्देशन के बिना आप को चलाते हैं , तो binaryस्टड को अपने मूल शेल से विरासत में मिला होगा, जो कि खुद को अपने मूल टर्मिनल एमुलेटर से विरासत में मिला होगा और एक अंतर्निहित होगा pty डिवाइस रीड + राइट मोड (कुछ इस तरह /dev/pts/n) में खुली ।

उन उपकरणों को खोजने योग्य नहीं हैं। इसलिए, यदि binaryटर्मिनल से इनपुट लेते समय ओके काम करता है , तो संभवतः समस्या मांगने के बारे में नहीं है।

यदि उस 14 का मतलब एक इरानो (एक त्रुटि कोड जिसे सिस्टम कॉल को विफल करके निर्धारित किया गया है) है, तो अधिकांश प्रणालियों पर, यह EFAULT( खराब पता ) होगा। read()सिस्टम कॉल कि त्रुटि के साथ विफल अगर एक स्मृति पता है कि लिखने योग्य नहीं है में पढ़ने के लिए कहा जाएगा। यह स्वतंत्र होगा कि क्या एक बिंदु से पाइप या नियमित फ़ाइल के डेटा को पढ़ने के लिए fd और आमतौर पर बग 1 इंगित करेगा ।

binaryसंभवतया इसकी स्टड (साथ fstat()) पर खुली हुई फ़ाइल का प्रकार निर्धारित करता है और बग में चलता है जब यह न तो एक नियमित फ़ाइल है और न ही एक टटी डिवाइस है।

आवेदन के बारे में अधिक जानने के बिना बताना मुश्किल है। के तहत यह चल रहा है strace(या truss/ tuscअपने सिस्टम पर समकक्ष) मदद कर सकता है आइए देखें कि सिस्टम कॉल है क्या हुआ अगर किसी भी है कि यहाँ विफल हो रहा है।


1 आपके प्रश्न के लिए एक टिप्पणी में मैथ्यू इफ द्वारा परिकल्पित परिदृश्य यहाँ बहुत प्रशंसनीय लगता है। उसे उद्धृत करते हुए:

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


14
बहुत दिलचस्प ... यह पहली बार है जब मैंने सुना है कि पुनर्निर्देशित मानक इनपुट शैली की ./binary < fileतलाश में है!
डेविड जेड

2
@DavidZ यह एक ऐसी फाइल है जो openएड की गई है और यह एड की गई किसी भी फाइल की तरह ही व्यवहार करती है open। यह सिर्फ एक मूल प्रक्रिया से विरासत में मिला होता है, लेकिन यह इतना असामान्य नहीं है।
हॉब्स

3
यदि सिस्टम में स्ट्रेस या एक समान टूल होता है, तो इसका उपयोग यह जांचने के लिए किया जा सकता है कि सिस्टम किस बाइनरी को कॉल करता है।
पाबौक

2
"यह इसे छोटा भी कर सकता है, इसे mmap कर सकता है, इसमें छिद्र छेद कर सकता है आदि।" - नहीं। फ़ाइल केवल-पढ़ने के लिए मोड में खुली है। कार्यक्रम को ऐसा करने के लिए इसे लेखन मोड में खोलना होगा। लेकिन यह इसे लिखित रूप में नहीं खोल सकता है, क्योंकि ऐसा करने के लिए कोई इंटरफ़ेस सीधे नहीं है, और न ही "निर्देशिका" प्रविष्टि को खोजने के लिए कोई इंटरफ़ेस है जो एक खुली फ़ाइल से मेल खाती है (क्या होगा यदि इस तरह के दो डेन्चर, या शून्य हैं?) । यह फ़ाइल को स्टेट करना होगा और फिर उसी इनोड नंबर के साथ किसी ऑब्जेक्ट के लिए फाइल सिस्टम को स्कैन करना होगा। यह बहुत ही धीमी गति से होगा।
केविन

1
@ StéphaneChazelas: ओह ठीक है, open("/proc/self/fd/0", O_RDWR)काम करता है, यहां तक ​​कि हटाई गई फ़ाइलों पर भी। मूर्खतापूर्ण मुझे: पी। इससे पहले कि echo foo>foo; (sleep 0.5; ll -L /proc/self/fd/0; strace ./a.out; ll -L /proc/self/fd/0) < foo & sleep 0.1 && rm fooअनलिंक fooचलता है, इसके स्टाइन से पुनर्निर्देशित होता है foo
पीटर कॉर्डेस

46

यहाँ एक सरल उदाहरण कार्यक्रम है जो अपने इनपुट पर स्टीफन चेज़लस के उत्तर का चित्रण lseek(2)करता है:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(void)
{
    int c;
    off_t off;
    off = lseek(0, 10, SEEK_SET);
    if (off == -1)
    {
        perror("Error");
        return -1;
    }
    c = getchar();
    printf("%c\n", c);
}

परिक्षण:

$ make seek
cc     seek.c   -o seek
$ cat foo
abcdefghijklmnopqrstuwxyz
$ ./seek < foo
k
$ ./seek <<EOF
> abcdefghijklmnopqrstuvwxyz
> EOF
k
$ cat foo | ./seek
Error: Illegal seek

पाइप खोज योग्य नहीं हैं, और यह एक जगह है जहां एक कार्यक्रम पाइप के बारे में शिकायत कर सकता है।


21

पाइप और पुनर्निर्देशन अलग-अलग जानवर हैं, इसलिए बोलने के लिए। जब आप here-docरीडायरेक्शन ( <<) या रीडायरेक्टिंग स्टडिन < का उपयोग करते हैं , तो टेक्स्ट पतली हवा से बाहर नहीं आता है - यह वास्तव में एक फाइल डिस्क्रिप्टर (या अस्थायी फ़ाइल, यदि आप होगा) में चला जाता है, और वह वह जगह है जहाँ बाइनरी स्टड इंगित कर रहा होगा।

विशेष रूप से, यहाँ bash'sस्रोत कोड से एक अंश है , redir.c फ़ाइल (संस्करण 4.3):

/* Create a temporary file holding the text of the here document pointed to
   by REDIRECTEE, and return a file descriptor open for reading to the temp
   file.  Return -1 on any error, and make sure errno is set appropriately. */
static int
here_document_to_fd (redirectee, ri)

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

पाइप्स, चूंकि वे 4096 बाइट्स या कम परमाणु होने की गारंटी के साथ 64 KiB (कम से कम लिनक्स पर) के बफ़र हैं, खोज योग्य नहीं हैं, यानी आप स्वतंत्र रूप से उन्हें नेविगेट नहीं कर सकते हैं - केवल क्रमिक रूप से पढ़ें। मैंने एक बार tailअजगर में आज्ञा लागू की । पाठ की 29 मिलियन लाइनों को रीडायरेक्ट होने पर माइक्रोसेकंड में खोजा जा सकता है, लेकिन अगर catपाइप के माध्यम से एड, ठीक है, तो ऐसा कुछ भी नहीं है जो किया जा सकता है - इसलिए इसे सभी को क्रमिक रूप से पढ़ना होगा।

एक और संभावना यह है कि बाइनरी विशेष रूप से एक फ़ाइल खोलना चाहता है, और पाइप से इनपुट प्राप्त नहीं करना चाहता है। यह आमतौर पर fstat()सिस्टम कॉल के माध्यम से किया जाता है , और अगर इनपुट एक S_ISFIFOप्रकार की फ़ाइल (जो एक पाइप / नामित पाइप का प्रतीक है) से आती है, तो यह जांचना ।

आपका विशिष्ट द्विआधारी, क्योंकि हम नहीं जानते कि यह क्या है, शायद कोशिश करना चाहता है, लेकिन पाइप की तलाश नहीं कर सकता। यह अनुशंसा की जाती है कि आप इसके दस्तावेज़ीकरण से यह जानने के लिए परामर्श करें कि वास्तव में त्रुटि कोड 14 का अर्थ क्या है।

नोट : कुछ गोले, जैसे कि डैश (डेबियन अल्मक्विस्ट शेल, /bin/shउबंटू पर डिफ़ॉल्ट ) आंतरिक रूपhere-doc से पाइप के साथ पुनर्निर्देशन को लागू करते हैं , इस प्रकार यह संभव नहीं हो सकता है। बिंदु समान रहता है - पाइप अनुक्रमिक हैं और आसानी से नेविगेट नहीं किया जा सकता है, और ऐसा करने का प्रयास त्रुटियों का परिणाम होगा।


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

@PeterCordes जो बिल्कुल ऐसा है, और मैंने इसे dashअपने सिस्टम पर सत्यापित किया है। मुझे उस बारे में पहले से जानकारी नहीं थी। इशारा करने के लिए धन्यवाद
सर्जियो कोलोडियाज़नी

एक और टिप्पणी: आप fstat()यह जाँचने के लिए स्टड पर उपयोग करेंगे कि क्या यह एक पाइप है। statएक पाथनाम लेता है। लेकिन वास्तव में, केवल lseekयह निर्धारित करने का सबसे अधिक संभव तरीका है कि अगर यह पहले से ही खुला है तो एक fd खोजे जाने योग्य है।
पीटर कॉर्डेस

5

मुख्य अंतर त्रुटि हैंडलिंग में है।

निम्नलिखित मामले में त्रुटि बताई गई है

$ /bin/cat < z.txt
-bash: z.txt: No such file or directory
$ echo $?
1

निम्नलिखित मामले में त्रुटि की सूचना नहीं है।

$ cat z.txt | /bin/cat
cat: z.txt: No such file or directory
$ echo $?
0

बैश के साथ, आप अभी भी PIPESTATUS का उपयोग कर सकते हैं:

$ cat z.txt | /bin/cat
cat: z.txt: No such file or directory
$ echo ${PIPESTATUS[0]}
1

लेकिन यह कमांड के निष्पादन के तुरंत बाद उपलब्ध है:

$ cat z.txt | /bin/cat
cat: z.txt: No such file or directory
$ echo $?
0
$ echo ${PIPESTATUS[0]}
0
# oops !

एक और अंतर है, जब हम बायनेरिज़ के बजाय शेल फ़ंक्शन का उपयोग करते हैं। उन bashकार्यों में , जो एक पाइपलाइन का हिस्सा हैं, सब-शेल में निष्पादित किए जाते हैं (अंतिम पाइपलाइन घटक को छोड़कर यदि lastpipeविकल्प सक्षम है और bashगैर-संवादात्मक है), इसलिए चर के परिवर्तन का मूल शेल में कोई प्रभाव नहीं है:

$ a=a
$ b=b
$ x(){ a=x;}
$ y(){ b=y;}

$ echo $a $b
a b

$ x | y
$ echo $a $b
a b

$ cat t.txt | y
$ echo $a $b
a b

$ x | cat
$ echo $a $b
a b

$ x < t.txt
$ y < t.txt
$ echo $a $b
x y

4
तो, आप दिखा रहे हैं कि त्रुटि से निपटने >शेल द्वारा किया जाता है, लेकिन पाइप के साथ यह कमांड द्वारा किया जाता है जो पाठ का उत्पादन करता है। ठीक। लेकिन इस विशिष्ट प्रश्न में, ओपी एक मौजूदा फ़ाइल का उपयोग कर रहा है, इसलिए यह मुद्दा नहीं है, और स्पष्ट रूप से उत्पन्न त्रुटि बाइनरी है।
सेर्गेई कोलोडियाज़नी

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

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