কমান্ড লাইন প্রোগ্রামের আউটপুটটিকে পুনঃনির্দেশিত করা আটকাতে পারে?


49

আমি এটি করতে অভ্যস্ত হয়ে উঠছি: someprogram >output.file

যখনই আমি কোনও প্রোগ্রাম কোনও ফাইলের উত্পন্ন আউটপুট সংরক্ষণ করতে চাই তখনই এটি করি। আমি এই আইও পুনঃনির্দেশের দুটি রূপ সম্পর্কেও সচেতন :

  • someprogram 2>output.of.stderr.file (স্টাডারের জন্য)
  • someprogram &>output.stderr.and.stdout.file (উভয় stdout + stderr এর জন্য)

আজ আমি এমন একটি পরিস্থিতি পেরিয়ে এসেছি যা আমি সম্ভব বলে ভাবিনি। আমি নিম্নলিখিত কমান্ডটি ব্যবহার করি xinput test 10এবং প্রত্যাশার সাথে আমার নিম্নলিখিত আউটপুট থাকে:

ব্যবহারকারী @ হোস্টনাম: in in এক্সপুট পরীক্ষা 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প্রোগ্রামটির আউটপুটটিকে পুনঃনির্দেশিত করা এড়াতে কোনও উপায় থাকতে পারে?

হালনাগাদ

আমি উত্স তাকিয়ে আছে। দেখে মনে হচ্ছে আউটপুটটি এই কোডটি দ্বারা উত্পাদিত হয়েছে (নীচে স্নিপেট দেখুন)। আমার কাছে মনে হচ্ছে আউটপুটটি একটি সাধারণ মুদ্রণযোগ্য দ্বারা উত্পাদিত হবে

// ফাইল টেস্ট.সি

স্ট্যাটিক অকার্যকর মুদ্রণ_আভেন্টস (প্রদর্শন * ডিপিপি)
{
    এক্সভেন্ট ইভেন্ট;

    (1) while
    এক্সনেক্সট ইভেন্ট (ডিপিপি, এবং ইভেন্ট);

    // [... কিছু অন্যান্য ইভেন্টের ধরন এখানে বাদ দেওয়া হয়েছে ...]

        যদি ((ইভেন্ট.প্রকার == কী_প্রেস_প্রকার)) ||
           (ইভেন্ট.প্রকার == কী_প্রথম_প্রকার)) {
        int লুপ;
        এক্সডেভাইসকিউইভেন্ট * কী = (এক্সডেভাইসকিউভেস্ট *) & ইভেন্ট;

        প্রিন্টফ ("কী% s% d", (ইভেন্ট. টাইপ == কী_ রিলিজ_ টাইপ)? "রিলিজ": "টিপুন", কী-> কীকোড);

        (লুপ = 0; লুপপ্যাক্স_কাউন্ট; লুপ ++) এর জন্য {
        প্রিন্টফ ("এ [% ডি] =% ডি", কী-> ফার্স্ট_এক্সিস + লুপ, কী-> অক্ষ_ডাটা [লুপ]);
        }
        printf, ( "\ N");
    } 
    }
}

আমি উত্সটি এটিতে পরিবর্তিত করেছি (নীচের পরবর্তী স্নিপেটটি দেখুন), যা আমাকে স্ট্ডারারের আউটপুটটির একটি অনুলিপি রাখতে দেয়। এই আউটপুট আমি পুনঃনির্দেশ করতে সক্ষম:

 // ফাইল টেস্ট.সি

স্ট্যাটিক অকার্যকর মুদ্রণ_আভেন্টস (প্রদর্শন * ডিপিপি)
{
    এক্সভেন্ট ইভেন্ট;

    (1) while
    এক্সনেক্সট ইভেন্ট (ডিপিপি, এবং ইভেন্ট);

    // [... কিছু অন্যান্য ইভেন্টের ধরন এখানে বাদ দেওয়া হয়েছে ...]

        যদি ((ইভেন্ট.প্রকার == কী_প্রেস_প্রকার)) ||
           (ইভেন্ট.প্রকার == কী_প্রথম_প্রকার)) {
        int লুপ;
        এক্সডেভাইসকিউইভেন্ট * কী = (এক্সডেভাইসকিউভেস্ট *) & ইভেন্ট;

        প্রিন্টফ ("কী% s% d", (ইভেন্ট. টাইপ == কী_ রিলিজ_ টাইপ)? "রিলিজ": "টিপুন", কী-> কীকোড);
        fprintf (stderr, "key% s% d", (ইভেন্ট. টাইপ == কী_ রিলিজ_ টাইপ)? "রিলিজ": "টিপুন", কী-> কীকোড);

        (লুপ = 0; লুপপ্যাক্স_কাউন্ট; লুপ ++) এর জন্য {
        প্রিন্টফ ("এ [% ডি] =% ডি", কী-> ফার্স্ট_এক্সিস + লুপ, কী-> অক্ষ_ডাটা [লুপ]);
        }
        printf, ( "\ N");
    } 
    }
}

বর্তমানে আমার ধারণাটি হ'ল পুনর্নির্দেশটি করে প্রোগ্রামটি কী-প্রেস কী-রিলিজ ইভেন্টগুলি পর্যবেক্ষণ করার ক্ষমতা হারাবে।

উত্তর:


55

এটি ঠিক যে যখন স্টডআউটটি টার্মিনাল নয়, আউটপুট বাফার হয়।

এবং আপনি যখন টিপেন Ctrl-C, সেই বাফারটি হারিয়ে গেছে / যদি এটি এখনও লেখা হয় নি।

আপনি যে কোনও কিছু ব্যবহার করে একই আচরণ পান stdio। উদাহরণস্বরূপ চেষ্টা করুন:

grep . > file

কয়েকটি খালি খালি লাইন লিখুন এবং টিপুন Ctrl-Cএবং আপনি ফাইলটি খালি দেখতে পাবেন।

অন্যদিকে, টাইপ করুন:

xinput test 10 > file

এবং বাফারটি পূর্ণ হওয়ার জন্য কীবোর্ডে যথেষ্ট টাইপ করুন (কমপক্ষে 4k মূল্য আউটপুট) এবং আপনি একবারে 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

এই সাইটে অনেকগুলি প্রশ্ন রয়েছে যেগুলি স্টিডিও টাইপ বাফারিং অক্ষম করে যেখানে আপনি আরও বিকল্প সমাধান খুঁজে পাবেন cover


2
বাহ :) যে কৌশলটি করেছে। ধন্যবাদ. সুতরাং শেষ পর্যন্ত আমার সমস্যাটি সম্পর্কে ধারণাটি ভুল ছিল। পুনঃনির্দেশকে বাধা দেওয়ার মতো জায়গায় তেমন কিছুই ছিল না, ডেটা ফ্লাশ হওয়ার আগে এটি সাধারণ সিটিআরএল-সি থামিয়ে দিয়েছিল। তোমাকে ধন্যবাদ
humanityANDpeace

স্ট্যাডআউট বাফারিং প্রতিরোধের জন্য কি কোনও উপায় থাকত?
মানবতাআন্ডপিস

1
@ স্টাফেন চেজেলাস: আপনার বিস্তারিত ব্যাখ্যার জন্য অনেক ধন্যবাদ। আপনি ইতিমধ্যে যা বলেছিলেন তা ছাড়াও আমি জানতে পেরেছি যে কেউ বাফারটি আনবুফার করতে পারবেন না setvbuf(stdout, (char *) NULL, _IONBF, NULL)। সম্ভবত এটিও আগ্রহের বিষয় !?
ব্যবহারকারী 1146332

4
@ ব্যবহারকারী ১১৪63৩৩৩, হ্যাঁ, এটিই হবে stdbuf -o0, যখন আউটপুট যখন টার্মিনালে যায় তখন লাইনের বাফারিং stdbug -oLপুনরুদ্ধার করে। একটি কৌশল ব্যবহার করে অ্যাপ্লিকেশনটিকে কল করতে বাধ্য করে । stdbufsetvbufLD_PRELOAD
স্টাফেন চেজেলাস

আরেকটি workaroudn: 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

আপনার উদাহরণটি + প্রশ্নের উত্তর দেয়। হ্যা এটা সম্ভব. প্রোগ্রামগুলি অবশ্যই এটির জন্য "অপ্রত্যাশিত" এবং অস্বাভাবিক, যা কমপক্ষে আমাকে এ জাতীয় কোনও সম্ভাব্য বিষয় বিবেচনা না করে বোকা বানিয়েছে। ব্যবহারকারী 1146332 এর উত্তর পুনঃনির্দেশ এড়ানোর একটি দৃinc়পদ উপায় বলে মনে হচ্ছে। সুষ্ঠু হতে এবং যেহেতু প্রদত্ত উভয় উত্তরই কোনও ফাইলের কাছে কমান্ড লাইন প্রোগ্রামের আউটপুটকে পুনঃনির্দেশ এড়ানোর জন্য সমান সম্ভাব্য উপায় আমি আমার অনুমানের যে কোনও উত্তর নির্বাচন করতে পারি না :( আমাকে দুটি উত্তর সঠিকভাবে নির্বাচন করার অনুমতি দেওয়া দরকার। দুর্দান্ত কাজ, আপনাকে ধন্যবাদ!
humanityANDpeace

1
এফটিআর, যদি আপনি /dev/ttyলিনাক্স সিস্টেমে লিখিত আউটপুট ক্যাপচার করতে চান তবে script -c ./demo demo.log(থেকে util-linux) ব্যবহার করুন ।
ndim

আপনি যদি টিটিটিতে চালাচ্ছেন না, তবে একটি পিটিআইয়ের পরিবর্তে, আপনি প্রোফস (/ proc / $ পিআইডি / এফডি / 0 ইত্যাদি) দেখে এটি সন্ধান করতে পারেন। যথাযথ পিটিআইতে লিখতে, আপনার পিতামাতার প্রসেসের এফডি ডিরেক্টরিতে যান এবং দেখুন এটি / dev / pts / [0-9] + এ একটি সিমলিংক কিনা। তারপরে আপনি সেই ডিভাইসে লিখুন (বা এটি যদি পিটিএস না হয় তবে পুনরাবৃত্তি করুন)।
ধাসানান

9

দেখে মনে হচ্ছে xinputকোনও ফাইলের আউটপুট প্রত্যাখ্যান করে তবে টার্মিনালে আউটপুট প্রত্যাখ্যান করে না। এটি অর্জন করতে সম্ভবত xinputসিস্টেম কলটি ব্যবহার করুন

int isatty(int fd)

ফাইলডেস্ক্রিপ্টারটি খোলার জন্য একটি টার্মিনাল বোঝায় কিনা তা পরীক্ষা করতে।

আমি একই ঘটনাকে হোঁচট খেয়েছিলাম কিছুক্ষণ আগে একটি প্রোগ্রামের সাথে dpic। উত্সটি অনুসন্ধান করার পরে এবং কিছু ডিবাগিংয়ের পরে আমি সম্পর্কিত লাইনগুলি সরিয়ে দিয়েছি isattyএবং সবকিছু প্রত্যাশা অনুযায়ী কাজ করেছে।

তবে আমি আপনার সাথে একমত হই যে এই অভিজ্ঞতাটি খুব ঝামেলার;)


আমি সত্যিই আমার এক্সপ্লেশন ভেবেছিলাম। তবে (1) উত্সটির দিকে তাকানো (এক্সপুট উত্স প্যাকেজে টেস্ট.সি ফাইল) isattyপরীক্ষা করার কোনও উপস্থিতি নেই । আউটপুটটি printfফাংশন দ্বারা উত্পাদিত হয় (আমি মনে করি এটি একটি স্ট্যান্ডার্ড সি) এক। আমি কিছু যুক্ত করেছি fprintf(stderr,"output")এবং এটি পুনঃনির্দেশ করা সম্ভব is পুরো কোডটি জিনপুট ক্ষেত্রে সত্যই চালু রয়েছে তা প্রমাণ করে। এটি এখানে প্রথম ট্রেইল হওয়ার পরেও পরামর্শের জন্য আপনাকে ধন্যবাদ।
মানবতাআন্ডপিস

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সিউডো টার্মিনাল (পিটিআই) চালিয়ে লাইন-বাফার আউটপুট সক্ষম করতে পারেন 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 এ আউটপুট লিখুন

এটি কোনও পাইপকে ভেঙে ফেলল।


"পুনরায় ওপেন স্ট্ডআউট": স্টডআউটটি ফাইল বর্ণনাকারী হিসাবে সংজ্ঞায়িত করা হয়। আপনি ফাইল বিবরণী ১ পুনরায় খুলতে পারেন, তবে আপনি কোন ফাইলটি খুলবেন? আপনার সম্ভবত সম্ভবত টার্মিনালটি উন্মুক্ত করা উচিত, এক্ষেত্রে প্রোগ্রামটি ১
ম এফডিতে

@ গিলস ফাইলটি "কন:" ছিল যতদূর আমার মনে আছে - তবে হ্যাঁ, আমি সেই দিকের পয়েন্ট 2 পরিমার্জন করেছি।
নীল

conইউনিক্স কল করার জন্য ডসের নাম /dev/tty, যেমন (নিয়ন্ত্রণকারী) টার্মিনাল।
গিলস 'অসন্তুষ্ট হওয়া বন্ধ করুন'
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.