खिड़कियों में, क्या मैं कमांड लाइन में एक (नामित) पाइप के लिए stdout को पुनर्निर्देशित कर सकता हूं?


18

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

अर्थात। पसंद है example.exe >\\.\mypipe। (यह वाक्यविन्यास सही नहीं हो सकता है, लेकिन आपको बिंदु मिल जाएगा।) मैं एक ही समय में अलग-अलग पाइपों के लिए stdout और stderr को पुनर्निर्देशित करने में सक्षम होना चाहूंगा ।

मैं एक विकल्प के रूप में भौतिक फ़ाइलों का उपयोग करने से बचना चाहूंगा, IO धीमापन, IO बफ़र्स, फ़ाइल लॉक, एक्सेस अधिकार, उपलब्ध हार्ड डिस्क स्थान, अधिलेखित करने का निर्णय, अनमना हठ, आदि से बचने के लिए।

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

अंत में, एक जिज्ञासा है कि क्या एक अच्छी अवधारणा को अच्छे उपयोग में लाया जा सकता है।


1
आप एक नामित पाइप या एक मेल्स्लेट को पुनर्निर्देशित करना पसंद करते हैं? क्या आप प्राप्त अंत लिखने के लिए तैयार हैं / हैं?
ixe013

हां, एक नामित पाइप या मेल्लॉट की तरह। मेरे पास अभी तक नहीं है लेकिन प्राप्त अंत लिखने के लिए तैयार है।
n611x007 10

जवाबों:


8

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


नाम दिया गया पाइप

मैंने क्या किया था।नेट 4 के लिए दो कार्यक्रम लिखे थे। एक नामांकित पाइप को आउटपुट भेजता है, दूसरा इस पाइप से पढ़ता है और कंसोल को प्रदर्शित करता है। उपयोग काफी सरल है:

asdf.exe | NamedPipeServer.exe "APipeName"

एक और कंसोल विंडो में:

NamedPipeClient.exe "APipeName"

दुर्भाग्य से, यह विंडोज ऑपरेटर प्रॉम्प्ट में पाइप ऑपरेटर ( ) में सीमाओं के कारण केवल पुनर्निर्देशित कर सकता है stdout(या stdinसंयुक्त), stderrअपने आप से नहीं |। यदि आप यह जानते हैं stderrकि उस पाइप ऑपरेटर के माध्यम से कैसे भेजा जाए , तो यह काम करना चाहिए। वैकल्पिक रूप से, सर्वर को आपके प्रोग्राम और विशेष रूप से पुनर्निर्देशित करने के लिए संशोधित किया जा सकता है stderr। यदि यह आवश्यक है, तो मुझे एक टिप्पणी में बताएं (या इसे स्वयं करें); यदि आपके पास कुछ C # और .NET "प्रोसेस" लाइब्रेरी नॉलेज है तो यह बहुत मुश्किल नहीं है।

आप सर्वर और क्लाइंट को डाउनलोड कर सकते हैं ।

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

सोर्स कोड

ये C # में लिखे गए हैं। इसको समझाने की कोशिश में ज्यादा बात नहीं है। वे .NET NamedPipeServerStream और NamedPipeClientStream का उपयोग करते हैं ।

सर्वर:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Pipes;
using System.IO;

namespace NamedPipeServer
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args == null || args.Length == 0)
            {
                Console.Error.WriteLine("[NamedPipeServer]: Need pipe name.");
                return;
            }

            NamedPipeServerStream PipeServer = new NamedPipeServerStream(args[0], System.IO.Pipes.PipeDirection.Out);
            PipeServer.WaitForConnection();
            StreamWriter PipeWriter = new StreamWriter(PipeServer);
            PipeWriter.AutoFlush = true;

            string tempWrite;

            while ((tempWrite = Console.ReadLine()) != null)
            {
                try
                {
                    PipeWriter.WriteLine(tempWrite);
                }
                catch (IOException ex)
                {
                    if (ex.Message == "Pipe is broken.")
                    {
                        Console.Error.WriteLine("[NamedPipeServer]: NamedPipeClient was closed, exiting");
                        return;
                    }
                }
            }

            PipeWriter.Close();
            PipeServer.Close();
        }
    }
}

ग्राहक:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Pipes;
using System.IO;

namespace NamedPipeClient
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args == null || args.Length == 0)
            {
                Console.Error.WriteLine("[NamedPipeClient]: Need pipe name.");
                return;
            }

            NamedPipeClientStream PipeClient = new NamedPipeClientStream(".", args[0], System.IO.Pipes.PipeDirection.In);
            PipeClient.Connect();
            StreamReader PipeReader = new StreamReader(PipeClient);

            string tempRead;

            while ((tempRead = PipeReader.ReadLine()) != null)
            {
                Console.WriteLine(tempRead);
            }

            PipeReader.Close();
            PipeClient.Close();
        }
    }
}

किसी फ़ाइल पर पुनर्निर्देशित करना

type NUL>StdErr.temp
start powershell -c Get-Content StdErr.temp -Wait
MyExecutable.exe 2>StdErr.temp
  1. एक खाली फ़ाइल बनाएँ
  2. एक नई कंसोल विंडो शुरू करें जो फ़ाइल को देखती है
  3. stderrउस फ़ाइल पर निष्पादन योग्य और पुनर्निर्देशित आउटपुट चलाएँ

यह देखने के लिए एक कंसोल विंडो का वांछित प्रभाव प्रदान करता है stdout(और प्रदान stdin), और दूसरा देखने के लिए stderr

कुछ भी है कि mimics tailकाम करेगा। PowerShell विधि विंडोज़ में मूल रूप से काम करती है, लेकिन थोड़ी धीमी हो सकती है (यानी फ़ाइल में लिखने और स्क्रीन को प्रदर्शित करने के बीच कुछ विलंबता)। अन्य विकल्पों के लिए इस StackOverflow प्रश्न को देखें tail

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


2
UNIX उपयोगकर्ता वे हैं जो नाराज हैं क्योंकि Windows 40 साल पुराने विचार को एक समझदार तरीके से लागू करने के लिए फिर से विफल रहता है। हर बार जब आप एक बुनियादी काम करना चाहते हैं तो आपको एक कस्टम प्रोग्राम लिखने की आवश्यकता नहीं होनी चाहिए। facepalm
bambams

नीचे देखें: आप नामित पाइप को सौंपे गए UNC पथ का उपयोग कर सकते हैं, और इसे सीधे एक्सेस कर सकते हैं।
एरिक एरोनेस्टी

16

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

program.exe >\\.\pipe\StdOutPipe 2>\\.\pipe\StdErrPipe

"StdOutPipe" और "StdErrPipe" नाम के पाइप इस मशीन पर मौजूद हैं, यह उन्हें जोड़ने और लिखने का प्रयास करता है। pipeभाग क्या यह बताता है कि आप एक नामित पाइप चाहते हैं।


मुझे लगता है कि इसे सही उत्तर के रूप में चिह्नित किया जाना चाहिए क्योंकि ऐसा करने के लिए बस @ n611x007 से बाहरी कार्यक्रमों की आवश्यकता नहीं है!
आर्टर्न

समस्या यह है कि आपको अभी भी किसी प्रकार की एक सेवा शुरू करने की आवश्यकता है जो उन पाइपों का निर्माण करती है .... वे उस प्रोग्राम के स्वतंत्र रूप से मौजूद नहीं हैं जो प्रोग्राम के चले जाने पर निर्मित और नष्ट हो जाते हैं।
एरिक एरोनेस्टी

@ ErikAronesty मैंने माना कि ये पाइप पहले से मौजूद हैं। अन्यथा, केवल cmd.exe के साथ उन्हें बनाने का कोई तरीका नहीं है।
IllidanS4, मोनिका को

हाँ, यह यूनिक्स पाइपों के बारे में अच्छी बात है, आप कमांड लाइन से पाइप बना सकते हैं
एरिक एरोनिटी

1

मानक शेल (CMD.EXE) के साथ नहीं। प्रोग्रामर के लिए, यह काफी आसान है । बस एक प्रक्रिया के दो पाइपों को पकड़ो जो आपने शुरू किया था।


1
केवल prb यह है कि नमूना गुमनाम पाइपों का उपयोग करता है, जो ओवरलैप किए गए io (async) का समर्थन नहीं करते हैं और इस प्रकार गतिरोध के लिए प्रवण होते हैं, या कम से कम PeekNamedPipe का उपयोग किया जाना चाहिए।
फर्नांडो गोंजालेज सांचेज

1
ब्लॉकिंग वेट गतिरोधी नहीं हैं, और मौलिक समस्या (डेटा उत्पादक थ्रेड निर्माता इसे उत्पादन करने से रोकता है) वैसे भी ओवरलैप किए गए I / O द्वारा हल नहीं किया जाता है।
MSalters

मेरा यह अर्थ था: blogs.msdn.com/b/oldnewthing/archive/2011/07/07/10183884.aspx , एक गतिरोध उदाहरण।
फर्नांडो गोंजालेज सांचेज

1
@FernandoGonzalezSanchez: बहुत ज्यादा एक ही समस्या है। ध्यान दें कि अनुशंसित समाधान (अतिरिक्त धागा) async I / O के लिए किसी भी आवश्यकता को रोक देता है।
8

1
हाँ, msdn नमूने में prb यह है कि अभिभावक हमेशा के लिए रुक जाता है, फ़ंक्शन ReadFromPipe, लाइन bSuccess = ReadFile (g_hChildStd_OUT_Rd, chBuf, BUFSIZE, और dwRead, NULL) में; 1 बार 70 बाइट्स पढ़ेंगे, और दूसरा समय हमेशा के लिए अटक जाएगा (PeekNamedPipe, जो गायब है, गैर अवरुद्ध है)।
फर्नांडो गोंजालेज सांचेज

-1

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

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