Di windows, bisakah saya mengarahkan stdout ke pipa (bernama) di baris perintah?

16

Apakah ada cara untuk mengarahkan output standar dari suatu proses di konsol Win32 ke pipa bernama ? Named pipes dibangun untuk Windows dan meskipun mereka akan menjadi konsep yang berguna, saya belum pernah melihatnya menggunakan baris perintah.

Yaitu. seperti example.exe >\\.\mypipe. (Sintaks ini mungkin tidak benar tetapi Anda mendapatkan intinya.) Saya ingin dapat mengarahkan stdout dan stderr ke pipa yang berbeda secara bersamaan.

Saya ingin menghindari menggunakan file fisik sebagai pengganti, untuk menghindari berurusan dengan kelambatan IO, buffer IO, kunci file, hak akses, ruang hard disk yang tersedia, keputusan untuk menimpa, kegigihan yang tidak berarti, dll.

Alasan lain adalah karena seperangkat alat Windows tradisional tidak dirancang di sekitar filosofi berbasis file (teks) sebanyak di Unix . Selain itu, pipa bernama tidak dapat dengan mudah dipasang di Windows, jika sama sekali.

Akhirnya, ada rasa ingin tahu jika konsep yang baik dapat dimanfaatkan dengan baik.

n611x007
sumber
1
Maksud Anda seperti mengarahkan ke pipa bernama atau tempat surat? Apakah Anda memiliki / mau menulis akhir penerima?
ixe013
Ya, suka ke pipa bernama atau tempat surat. Saya belum memiliki tetapi bersedia untuk menulis akhir penerima.
n611x007

Jawaban:

8

Saya tidak yakin mengapa Anda tidak ingin mengalihkan ke file. Ada dua metode yang akan saya berikan di sini. Salah satu metode adalah untuk mengarahkan ulang dan membaca dari file, yang lain adalah serangkaian program.


Bernama pipa

Apa yang saya lakukan adalah menulis dua program untuk .NET 4. Satu mengirimkan output ke pipa bernama, yang lain membaca dari pipa ini dan menampilkan ke konsol. Penggunaannya cukup sederhana:

asdf.exe | NamedPipeServer.exe "APipeName"

Di jendela konsol lain:

NamedPipeClient.exe "APipeName"

Sayangnya, ini hanya dapat mengarahkan ulang stdout(atau stdin, atau dikombinasikan), bukan stderrdengan sendirinya, karena keterbatasan dalam operator pipa ( |) di Prompt Perintah Windows. Jika Anda mengetahui cara mengirim stderrmelalui operator pipa itu, itu akan berhasil. Atau, server dapat dimodifikasi untuk meluncurkan program Anda dan secara khusus mengarahkan ulang stderr. Jika itu perlu, beri tahu saya dalam komentar (atau lakukan sendiri); tidak terlalu sulit jika Anda memiliki pengetahuan pustaka C # dan .NET "Process".

Anda dapat mengunduh server dan klien .

Jika Anda menutup server setelah koneksi, klien akan segera menutup. Jika Anda menutup klien setelah koneksi, server akan menutup segera setelah Anda mencoba mengirim sesuatu melaluinya. Tidak mungkin untuk menyambungkan kembali pipa yang rusak, terutama karena saya tidak dapat diganggu melakukan sesuatu yang begitu rumit sekarang. Ini juga terbatas pada satu klien per server .

Kode sumber

Ini ditulis dalam C #. Tidak banyak gunanya mencoba menjelaskannya. Mereka menggunakan .NET NamedPipeServerStream dan NamedPipeClientStream .

Server:

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

Klien:

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

Mengarahkan kembali ke file

type NUL>StdErr.temp
start powershell -c Get-Content StdErr.temp -Wait
MyExecutable.exe 2>StdErr.temp
  1. Buat file kosong
  2. Mulai jendela konsol baru yang menonton file
  3. Jalankan stderroutput yang dapat dieksekusi dan arahkan ke file itu

Ini memberikan efek yang diinginkan dari satu jendela konsol untuk menonton stdout(dan menyediakan stdin), dan lainnya untuk menonton stderr.

Apa pun yang meniru tailakan berhasil. Metode PowerShell bekerja secara asli di Windows, tetapi mungkin agak lambat (yaitu ada beberapa latensi antara penulisan ke file dan tampilan ke layar). Lihat pertanyaan StackOverflow ini untuk tailalternatif lain .

Satu-satunya masalah adalah file sementara dapat tumbuh cukup besar. Solusi yang mungkin adalah menjalankan loop yang hanya mencetak jika file memiliki konten dan menghapus file segera setelahnya, tetapi itu akan menyebabkan kondisi balapan.

Bob
sumber
2
Pengguna UNIX adalah orang-orang yang kesal karena Windows gagal lagi menerapkan ide berusia 40 tahun dengan cara yang masuk akal. Anda tidak perlu menulis program kustom setiap kali Anda ingin melakukan hal dasar. facepalm
bambams
Lihat di bawah: Anda dapat menggunakan jalur UNC yang ditetapkan untuk pipa bernama, dan mengaksesnya secara langsung.
Erik Aronesty
14

Saya terkejut bahwa ini belum dijawab dengan benar. Memang ada jalur UNC yang ditetapkan untuk pipa bernama oleh sistem, dapat diakses pada mesin apa pun dalam jaringan, yang dapat digunakan seperti file normal:

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

Dengan asumsi pipa bernama "StdOutPipe" dan "StdErrPipe" ada di mesin ini, ini mencoba menghubungkan dan menulis ke mereka. Bagian pipeinilah yang menentukan bahwa Anda menginginkan pipa bernama.

IllidanS4
sumber
Saya pikir ini harus ditandai sebagai jawaban yang benar karena Apakah hanya meminta @ n611x007 program eksternal tidak diperlukan untuk melakukan ini!
Arturn
masalahnya adalah bahwa Anda masih perlu meluncurkan layanan dari beberapa jenis yang membuat pipa-pipa itu .... mereka tidak ada secara independen dari program yang dibuat dan dihancurkan ketika program itu hilang.
Erik Aronesty
@ ErikAronesty Saya berasumsi pipa ini sudah ada. Kalau tidak, tidak ada cara untuk membuatnya hanya dengan cmd.exe.
IllidanS4
Ya itu yang keren tentang pipa unix, Anda dapat membuat pipa dari baris perintah
Erik Aronesty
1

Tidak dengan shell standar (CMD.EXE). Untuk programmer, ini cukup mudah . Hanya ambil dua pipa dari proses yang Anda mulai.

MSalters
sumber
1
Satunya prb adalah bahwa sampel menggunakan pipa anonim, yang tidak mendukung tumpang tindih io (async) dan karenanya rentan terhadap kebuntuan, atau setidaknya PeekNamedPipe harus digunakan.
Fernando Gonzalez Sanchez
1
Menunggu pemblokiran bukanlah jalan buntu, dan masalah mendasar (penghasil data memblokir penghasil thread dari memproduksinya) tidak diselesaikan dengan tumpang tindih I / O.
MSalters
Saya maksud ini: blogs.msdn.com/b/oldnewthing/archive/2011/07/07/10183884.aspx , contoh kebuntuan.
Fernando Gonzalez Sanchez
1
@FernandoGonzalezSanchez: Masalah yang hampir sama. Perhatikan bahwa solusi yang disarankan (utas ekstra) mengesampingkan segala kebutuhan untuk I / O async.
MSalters
1
Ya, prb dalam sampel msdn adalah bahwa orangtua macet selamanya menunggu, dalam fungsi ReadFromPipe, baris bSuccess = ReadFile (g_hChildStd_OUT_Rd, chBuf, BUFSIZE, & dwRead, NULL); akan membaca 70 byte 1 kali, dan 2 kali akan macet selamanya (PeekNamedPipe, yang hilang, tidak memblokir).
Fernando Gonzalez Sanchez
-2

Preferensi Anda untuk pipa data Windows dari server ke jendela dos klien baik segera atau lambat mungkin puas dengan drive RAM kecil. Memori yang sama dialokasikan untuk data, ditulis / dibaca dengan nama seperti sistem file. Klien menghapus file yang sudah habis dan menunggu yang lain, atau membiarkannya menghilang ketika komputer dimatikan.

pengguna999850
sumber