Windows'ta stdout'u komut satırındaki (adlı) bir boruya yeniden yönlendirebilir miyim?


18

Yönlendirmek için bir yolu var mı standart çıktıyı bir sürecin Win32 konsoluna a adlandırılmış yöneltme ? Adlandırılmış borular Windows'a yerleşiktir ve yararlı bir kavram olsa da, bunları komut satırından hiç kullanmadım.

Yani. gibi example.exe >\\.\mypipe. (Bu sözdizimi doğru olmayabilir ama anladınız.) Stdout ve stderr'ı aynı anda farklı borulara yönlendirebiliyorum .

Fiziksel dosyaları ikame olarak kullanmaktan kaçınmak, IO yavaşlığı, IO tamponları, dosya kilitleri, erişim hakları, kullanılabilir sabit disk alanı, üzerine yazma kararı, kalıcılık, vb.

Başka bir neden, geleneksel Windows araç setinin Unix'te olduğu gibi (metin) dosya tabanlı bir felsefe etrafında tasarlanmamış olmasıdır . Ayrıca, adlandırılmış borular Windows'a kolayca monte edilemedi.

Son olarak, iyi bir konseptin iyi bir şekilde kullanılabilmesi durumunda merak vardır.


1
Yani adlandırılmış bir boruya veya bir posta yuvasına yönlendirmek mi istiyorsunuz? Alıcının sonunu yazmak istiyor musunuz?
ixe013

Evet, adlandırılmış bir boru veya posta yuvası gibi. Henüz alıcı sonunu yazmak istemiyorum.
n611x007

Yanıtlar:


8

Neden bir dosyaya yönlendirmek istemediğinizden emin değilim. Burada sağlayacağım iki yöntem var. Bir yöntem bir dosyaya yönlendirme ve dosyadan okuma, diğeri ise bir dizi programdır.


Adlandırılmış borular

Yaptığım şey, .NET 4 için iki program yazmaktı. Biri adlandırılmış bir boruya çıktı gönderir, diğeri bu borudan okur ve konsola görüntüler. Kullanımı oldukça basit:

asdf.exe | NamedPipeServer.exe "APipeName"

Başka bir konsol penceresinde:

NamedPipeClient.exe "APipeName"

Ne yazık ki, bu , Windows Komut İstemi'ndeki boru operatörünün ( ) sınırlamaları nedeniyle yalnızca kendi başına değil yeniden yönlendirebilir stdout(veya stdinbirleştirebilir) . Bu boru operatörünü nasıl göndereceğinizi anlarsanız, çalışması gerekir. Alternatif olarak, sunucu programınızı başlatacak ve özellikle yeniden yönlendirecek şekilde değiştirilebilir . Bu gerekliyse, bir yorumda bana bildirin (veya kendiniz yapın); bazı C # ve .NET "İşlem" kitaplığı bilginiz varsa çok zor değil.stderr|stderrstderr

Sunucuyu ve istemciyi indirebilirsiniz .

Bağlantıdan sonra sunucuyu kapatırsanız, istemci hemen kapanacaktır. Bağlantıdan sonra istemciyi kapatırsanız, sunucu bir şey göndermeye çalıştığınızda kapanır. Kırık bir boruyu yeniden bağlamak mümkün değil, çünkü şu anda çok karmaşık bir şey yapmaktan rahatsız edilemiyorum. Ayrıca sunucu başına bir istemci ile sınırlıdır .

Kaynak kodu

Bunlar C # ile yazılmıştır. Bunu açıklamaya çalışmanın pek bir anlamı yok. .NET NamedPipeServerStream ve NamedPipeClientStream kullanırlar .

Sunucu:

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();
        }
    }
}

Müşteri:

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();
        }
    }
}

Bir dosyaya yönlendirme

type NUL>StdErr.temp
start powershell -c Get-Content StdErr.temp -Wait
MyExecutable.exe 2>StdErr.temp
  1. Boş bir dosya oluştur
  2. Dosyayı izleyen yeni bir konsol penceresi başlatın
  3. Yürütülebilir dosyayı çalıştırın ve stderrçıktıyı bu dosyaya yönlendirin

Bu, izlemek stdout(ve sağlamak stdin) için bir konsol penceresinin ve izlemek için başka bir konsol penceresinin istenen etkisini sağlar stderr.

Taklit eden her şey işe yarar tail. PowerShell yöntemi Windows'da yerel olarak çalışır, ancak biraz yavaş olabilir (yani, dosyaya yazma ile ekrana görüntüleme arasında bir miktar gecikme olabilir). Diğer alternatifler için bu StackOverflow sorusuna bakın tail.

Tek sorun geçici dosya oldukça büyüyebilir. Olası bir geçici çözüm, yalnızca dosyanın içeriğe sahip olması durumunda yazdırılan ve dosyayı hemen sonra temizleyen bir döngü çalıştırmaktır, ancak bu bir yarış durumuna neden olur.


2
UNIX kullanıcıları, Windows bir kez daha 40 yıllık bir fikri mantıklı bir şekilde uygulayamadığı için rahatsız olan kullanıcılardır. Her temel şeyi yapmak istediğinizde özel bir program yazmanıza gerek yoktur. facepalm
bambams

Aşağıya bakın: adlandırılmış bir boruya atanmış UNC yolunu kullanabilir ve doğrudan erişebilirsiniz.
Erik Aronesty

16

Bunun daha önce doğru bir şekilde yanıtlanmadığına şaşırdım. Gerçekten de sistem tarafından adlandırılmış kanallara atanan, ağdaki herhangi bir makinede erişilebilen ve normal bir dosya gibi kullanılabilen bir UNC yolu vardır :

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

Bu makinede "StdOutPipe" ve "StdErrPipe" adlı boruların var olduğu varsayılırsa, bu bağlantı onlara bağlanmaya ve yazmaya çalışır. pipeBölüm adlandırılmış yöneltme istediğinizi belirtir şeydir.


Sanırım bu doğru bir yanıt olarak işaretlenmeli, sadece n611x007 bunu soruyor mu? Bunu yapmak için harici programlar gerekli değildir!
17'de

sorun hala bu boruları oluşturan bir tür bir hizmet başlatmanız gerekir .... onlar oluşturulan ve program kaybolduğunda yok olan bir programdan bağımsız yok.
Erik Aronesty

@ErikAronesty Bu boruların zaten var olduğunu varsaydım. Aksi takdirde, yalnızca cmd.exe ile oluşturmanın bir yolu yoktur.
IllidanS4, Monica'nın

Evet, unix boruları ile ilgili harika bir şey, komut satırından boru oluşturabilirsiniz
Erik Aronesty 28:17

1

Standart kabuk (CMD.EXE) ile değil. Programcılar için oldukça kolaydır . Başladığınız bir işlemin iki borusunu alın.


1
Sadece prb, numunenin örtüşen io'yu (async) desteklemeyen ve dolayısıyla çıkmaza eğilimli anonim borular kullanması veya en azından PeekNamedPipe kullanılması gerektiğidir.
Fernando Gonzalez Sanchez

1
Bekleme engelleme kilitlenmeler değildir ve temel sorun (veri tüketen iş parçacığı üretici iş parçacığının bunu üretmesini engeller) üst üste bindirilmiş G / Ç tarafından çözülmez.
MSalters


1
@FernandoGonzalezSanchez: Hemen hemen aynı problem. Önerilen çözümün (ekstra iplik) zaman uyumsuz G / Ç ihtiyacını azalttığını unutmayın.
MSalters

1
Evet, msdn örneğindeki prb, üst öğenin sonsuza kadar beklemede kalması, ReadFromPipe işlevinde, satır bSuccess = ReadFile (g_hChildStd_OUT_Rd, chBuf, BUFSIZE & dwRead, NULL); 1. kez 70 bayt okuyacak ve 2. kez sonsuza kadar sıkışacak (eksik olan PeekNamedPipe engellemiyor).
Fernando Gonzalez Sanchez

-1

Bir sunucudan bir istemci dos penceresine hemen veya daha sonra bir Windows veri borusu tercihleriniz küçük bir RAM sürücüsünden memnun olabilir. Dosya sistemi benzeri bir adla yazılan / okunan veriler için aynı bellek ayrılır. İstemci, kullanılan dosyayı siler ve başka bir dosyayı bekler veya bilgisayar kapatıldığında kaybolmasını sağlar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.