क्या एक कमांड लाइन प्रोग्राम इसके उत्पादन को पुनर्निर्देशित होने से रोक सकता है?


49

मुझे ऐसा करने की आदत हो गई है: someprogram >output.file

मैं इसे तब करता हूं जब मैं उस आउटपुट को सहेजना चाहता हूं जो एक प्रोग्राम एक फ़ाइल में उत्पन्न करता है। मैं इस IO पुनर्निर्देशन के दो प्रकारों से भी अवगत हूँ :

  • someprogram 2>output.of.stderr.file (stderr के लिए)
  • someprogram &>output.stderr.and.stdout.file (दोनों stdout + stderr के लिए संयुक्त)

आज मैंने ऐसी स्थिति में भाग लिया है, जिसके बारे में मैंने सोचा ही नहीं था। मैं निम्नलिखित कमांड का उपयोग करता हूं xinput test 10और जैसा कि मुझे उम्मीद है कि मेरा निम्न आउटपुट है:

user @ hostname: ~ $ xinput test 10
कुंजी प्रेस 30 
प्रमुख रिलीज 30 
कुंजी प्रेस 40 
प्रमुख रिलीज 40 
कुंजी प्रेस 32 
प्रमुख रिलीज 32 
कुंजी प्रेस 65 
प्रमुख रिलीज 65 
कुंजी प्रेस 61 
प्रमुख रिलीज 61 
कुंजी प्रेस 31 
^ सी
उपयोगकर्ता @ होस्टनाम: ~ $ 

मुझे उम्मीद थी कि यह आउटपुट हमेशा की तरह एक फाइल में सेव किया जा सकता है xinput test 10 > output.file। लेकिन जब मेरी अपेक्षा के लिए गर्भनिरोधक फ़ाइल आउटपुट। फ़ाइल खाली रहती है। यह भी xinput test 10 &> output.fileसिर्फ यह सुनिश्चित करने के लिए सही है कि मैं stdout या stderr पर कुछ याद नहीं करता हूं।

मैं वास्तव में भ्रमित हूं और इसलिए यहां पूछ रहा हूं कि क्या xinputकार्यक्रम में इसके उत्पादन से बचने का कोई तरीका हो सकता है?

अपडेट करें

मैंने स्रोत पर गौर किया है। ऐसा लगता है कि आउटपुट इस कोड से उत्पन्न होता है (नीचे स्निपेट देखें)। यह मुझे लगता है कि उत्पादन एक साधारण प्रिंटफ द्वारा उत्पन्न किया जाएगा

// फ़ाइल test.c में

स्थिर शून्य प्रिंट_वेंट्स (प्रदर्शन * dpy)
{
    एक्सवेंट इवेंट;

    जबकि (1) {
    XNextEvent (dpy, और घटना);

    // [... कुछ अन्य घटना प्रकारों को यहां छोड़ दिया गया है ...]

        अगर (Event.type == key_press_type) ||
           (Event.type == key_release_type)) {
        इंट लूप;
        XDeviceKeyEvent * कुंजी = (XDeviceKeyEvent *) & घटना;

        प्रिंटफ ("कुंजी% s% d", (Event.type == key_release_type); "रिलीज़": "प्रेस", कुंजी-> कीकोड);

        (लूप = 0; लूपैक्स_काउंट; लूप ++) {
        प्रिंटफ ("[a% d] =% d", कुंजी-> first_axis + लूप, कुंजी-> axis_data [लूप]);
        }
        printf ( "\ n");
    } 
    }
}

मैंने इसके लिए स्रोत को संशोधित किया (नीचे अगला स्निपेट देखें), जो मुझे स्टैडर पर आउटपुट की एक प्रति रखने की अनुमति देता है। यह आउटपुट मैं पुनर्निर्देशित करने में सक्षम हूं:

 // फ़ाइल test.c में

स्थिर शून्य प्रिंट_वेंट्स (प्रदर्शन * dpy)
{
    एक्सवेंट इवेंट;

    जबकि (1) {
    XNextEvent (dpy, और घटना);

    // [... कुछ अन्य घटना प्रकारों को यहां छोड़ दिया गया है ...]

        अगर (Event.type == key_press_type) ||
           (Event.type == key_release_type)) {
        इंट लूप;
        XDeviceKeyEvent * कुंजी = (XDeviceKeyEvent *) & घटना;

        प्रिंटफ ("कुंजी% s% d", (Event.type == key_release_type); "रिलीज़": "प्रेस", कुंजी-> कीकोड);
        fprintf (stderr, "key% s% d", (Event.type == key_release_type)? "release": "press", key-> keycode);

        (लूप = 0; लूपैक्स_काउंट; लूप ++) {
        प्रिंटफ ("[a% d] =% d", कुंजी-> first_axis + लूप, कुंजी-> axis_data [लूप]);
        }
        printf ( "\ n");
    } 
    }
}

वर्तमान में मेरा विचार यह है कि शायद रीडायरेक्ट करने से प्रोग्राम की-प्रेस की-रिलीज़ घटनाओं की निगरानी करने की क्षमता खो देता है।

जवाबों:


55

यह सिर्फ इतना है कि जब स्टडआउट टर्मिनल नहीं है, तो आउटपुट बफर हो जाता है।

और जब आप दबाते हैं Ctrl-C, तो वह बफर खो जाता है / यदि यह अभी तक नहीं लिखा गया है।

आप किसी भी चीज़ का उपयोग करने के साथ एक जैसा व्यवहार करते हैं stdio। उदाहरण के लिए प्रयास करें:

grep . > file

कुछ गैर-रिक्त लाइनें दर्ज करें और दबाएं Ctrl-C, और आप देखेंगे कि फ़ाइल खाली है।

दूसरी ओर, टाइप करें:

xinput test 10 > file

और बफ़र के लिए कीबोर्ड पर पर्याप्त लिखें (पूर्ण रूप से कम से कम 4k ouput) प्राप्त करने के लिए, और आप एक बार में 4k के विखंडू द्वारा फ़ाइल के आकार को बढ़ते हुए देखेंगे ।

इसके साथ grep, आप इसके बफर को फ्लश करने के बाद इनायत से बाहर निकलने के Ctrl-Dलिए टाइप कर सकते हैं grep। के लिए xinput, मुझे नहीं लगता कि ऐसा कोई विकल्प है।

ध्यान दें कि डिफ़ॉल्ट रूप stderrसे बफर नहीं किया गया है जो बताता है कि आपको एक अलग व्यवहार क्यों मिलता हैfprintf(stderr)

यदि, xinput.cआप इसमें जोड़ते हैं, तो यह कहते हैं signal(SIGINT, exit)कि xinputजब यह प्राप्त होता है SIGINT, तो आप इनायत से बाहर निकलें , आप देखेंगे कि fileअब खाली नहीं है (यह मानते हुए कि यह दुर्घटनाग्रस्त नहीं होता है, क्योंकि सिग्नल हैंडलर से लाइब्रेरी फ़ंक्शन कॉल करना सुरक्षित नहीं है: विचार करें कि क्या यदि प्रिंटफ बफर को लिख रहा है तो सिग्नल आ सकता है)।

यदि यह उपलब्ध है, तो आप बफरिंग व्यवहार stdbufको बदलने के लिए कमांड का उपयोग कर सकते हैं stdio:

stdbuf -oL xinput test 10 > file

इस साइट पर कई सवाल हैं, जो stdio प्रकार को अक्षम करने को कवर करते हैं, जहाँ आपको और भी वैकल्पिक समाधान मिलेंगे।


2
वाह :) कि चाल है। धन्यवाद। इसलिए अंत में समस्या के बारे में मेरी धारणा गलत थी। पुनर्निर्देशन को रोकने के लिए जगह में कुछ भी नहीं था, डेटा के फ्लश होने से पहले इसे सरल Ctrl-C ने रोक दिया था। धन्यवाद
मानवतावाद

क्या स्टडआउट की बफ़रिंग को रोकने का कोई तरीका था?
मानवतावाद

1
@ स्टेफ़ेन चेज़लस: आपके विस्तृत विवरण के लिए बहुत बहुत धन्यवाद। इसके अलावा जो आपने पहले ही कहा है मुझे पता चला है कि बफर को अनफ़िल्टर्ड करने के लिए सेट कर सकते हैं setvbuf(stdout, (char *) NULL, _IONBF, NULL)। शायद यह भी रुचि है !?
user1146332

4
@ user1146332, हाँ, कि होगा क्या stdbuf -o0करता है, जबकि stdbug -oLपुनर्स्थापित लाइन की तरह जब उत्पादन एक टर्मिनल को जाता है बफरिंग। एक चाल का उपयोग करके stdbufकॉल करने के लिए एप्लिकेशन को बाध्य करता है । setvbufLD_PRELOAD
स्टीफन चेज़लस

एक और वर्कआर्डन: unbuffer test 10 > file( टूल्स unbufferका हिस्सा है expect)
ओलिवियर डुलैक

23

/dev/ttyनियमित रूप से होने वाली पुनर्निर्देशन को रोकने के लिए एक कमांड सीधे लिख सकता है।

$ cat demo
#!/bin/ksh
LC_ALL=C TZ=Z date > /dev/tty
$ ./demo >demo.out 2>demo.err
Fri Dec 28 10:31:57  2012
$ ls -l demo*
-rwxr-xr-x 1 jlliagre jlliagre 41 2012-12-28 11:31 demo
-rw-r--r-- 1 jlliagre jlliagre  0 2012-12-28 11:31 demo.err
-rw-r--r-- 1 jlliagre jlliagre  0 2012-12-28 11:31 demo.out

आपका उदाहरण बिंदु + प्रश्न का उत्तर देता है। हाँ यह संभव है। यह निश्चित रूप से ऐसा करने के लिए कार्यक्रमों के लिए "अप्रत्याशित" और uncommen है, जिसने कम से कम मुझे इस तरह की बात पर विचार करने में असमर्थ बनाया। User1146332 द्वारा उत्तर भी पुनर्निर्देशन से बचने का एक ठोस तरीका है। निष्पक्ष होना और चूंकि दोनों दिए गए जवाब समान रूप से संभव तरीके हैं कमांड लाइन प्रोग्राम आउटपुट के पुनर्निर्देशन से बचने के लिए एक फ़ाइल में मैं उन उत्तरों में से किसी का भी चयन नहीं कर सकता जो मुझे लगता है :(। मुझे दो उत्तरों का चयन करने की अनुमति होगी सही काम। महान काम। धन्यवाद!
मानवतावाद

1
FTR, यदि आप /dev/ttyलिनक्स सिस्टम पर लिखे आउटपुट को कैप्चर करना चाहते हैं, तो script -c ./demo demo.log(से util-linux) का उपयोग करें ।
ndim

यदि आप एक ट्टी में नहीं चल रहे हैं, लेकिन एक खटमल के बजाय, आप खरीद (/ खरीद / $ पीआईडी ​​/ एफडी / 0 आदि) को देखकर पा सकते हैं। उपयुक्त pty को लिखने के लिए, अपनी मूल प्रक्रिया की fd डायरेक्टरी में जाएं और देखें कि क्या वह / देव / pts / [0-9] + के लिए सहानुभूति है। फिर आप उस डिवाइस को लिखते हैं (या अगर यह एक पीटीएस नहीं है तो पुनरावृत्ति करें)।
धसानन

9

ऐसा लगता है कि xinputकिसी फ़ाइल के लिए आउटपुट को अस्वीकार कर देता है, लेकिन किसी टर्मिनल पर आउटपुट को अस्वीकार नहीं करता है। इसे प्राप्त करने के लिए, शायद xinputसिस्टम कॉल का उपयोग करें

int isatty(int fd)

यह जांचने के लिए कि क्या खोला जा सकता है कि दर्जकर्ता टर्मिनल को संदर्भित करता है या नहीं।

मैं थोड़ी देर पहले इसी कार्यक्रम में एक कार्यक्रम बुलाया गया था dpic। जब मैंने स्रोत में देखा और कुछ डिबगिंग के बाद मैंने उससे संबंधित लाइनों को हटा दिया isattyऔर सब कुछ फिर से उम्मीद के मुताबिक काम किया।

लेकिन मैं आपसे सहमत हूं कि यह अनुभव बहुत परेशान करने वाला है;)


मुझे वास्तव में लगा कि मेरी खोज है। लेकिन (1) स्रोत को देख रहे हैं (xinput स्रोत पैकेज में test.c फ़ाइल) किए गए isattyपरीक्षण की कोई उपस्थिति नहीं है। Ouput printfफ़ंक्शन द्वारा उत्पन्न होता है (मुझे लगता है कि यह एक मानक सी है) एक। मैंने कुछ जोड़ा fprintf(stderr,"output")और यह संभव है पुनर्निर्देशित + साबित करता है कि पूरे कोड को वास्तव में xinput के मामले में चलाया गया है। सुझाव के लिए धन्यवाद, आखिरकार यह पहला निशान था।
मानवतावाद

0

अपनी test.cफ़ाइल में आप (void)fflush(stdout);अपने printfबयानों के बाद सीधे बफ़र किए गए डेटा का उपयोग कर सकते हैं ।

    // in test.c
    printf("key %s %d ", (Event.type == key_release_type) ? "release" : "press  ", key->keycode);
    //fprintf(stderr,"key %s %d ", (Event.type == key_release_type) ? "release" : "press  ", key->keycode);
    //(void)fflush(NULL);
    (void)fflush(stdout);

कमांड लाइन पर आप कमांड के xinput test 10साथ छद्म टर्मिनल (pty) में चलकर लाइन-बफ़र आउटपुट को सक्षम कर सकते हैं script

script -q /dev/null xinput test 10 > file      # FreeBSD, Mac OS X
script -c "xinput test 10" /dev/null > file    # Linux

-1

हाँ। जब मैंने पास्कल में प्रोग्राम किया तो मैंने भी डॉस-बार में यही किया। मुझे लगता है कि सिद्धांत अभी भी धारण करता है:

  1. स्टडआउट बंद करें
  2. कंसोल के रूप में पुन: खोलें stdout
  3. आउटपुट को stdout में लिखें

इससे कोई पाइप टूट गया।


"पुनः खोलें stdout": stdout को फ़ाइल डिस्क्रिप्टर 1 के रूप में परिभाषित किया गया है। आप फ़ाइल डिस्क्रिप्टर 1 को फिर से खोल सकते हैं, लेकिन आप किस फ़ाइल को खोलेंगे? आप शायद टर्मिनल खोलते हैं, जिस स्थिति में यह कोई फर्क नहीं पड़ता कि क्या प्रोग्राम fd को लिख रहा है 1.
गाइल्स 'एसओ- बुराई को रोकें'

@ फाइल फ़ाइल "con:" है जहाँ तक मुझे याद है - लेकिन हाँ, मैंने उस दिशा में बिंदु 2 को परिष्कृत किया।
निल्स

conक्या यूनिक्स कॉल /dev/tty, यानी (नियंत्रित) टर्मिनल के लिए डॉस नाम है ।
गाइल्स का SO- दुष्ट होना बंद करो '
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.