Trong các cửa sổ, tôi có thể chuyển hướng thiết bị xuất chuẩn đến một ống (được đặt tên) trong dòng lệnh không?


17

Có cách nào để chuyển hướng đầu ra tiêu chuẩn của một quy trình trong bảng điều khiển Win32 sang một đường ống có tên không? Các đường ống được đặt tên được tích hợp vào Windows và mặc dù chúng sẽ là một khái niệm hữu ích, tôi chưa bao giờ thấy chúng được sử dụng từ dòng lệnh.

I E. như example.exe >\\.\mypipe. (Cú pháp này có thể không đúng nhưng bạn hiểu rõ.) Tôi muốn có thể chuyển hướng thiết bị xuất chuẩnthiết bị xuất chuẩn sang các đường ống khác nhau cùng một lúc.

Tôi muốn tránh sử dụng các tệp vật lý thay thế, để thoát khỏi việc xử lý sự chậm chạp của IO, bộ đệm IO, khóa tệp, quyền truy cập, dung lượng ổ cứng có sẵn, quyết định ghi đè, kiên trì không kiểm soát, v.v.

Một lý do khác là vì bộ công cụ Windows truyền thống không được thiết kế xung quanh triết lý dựa trên tệp (văn bản) nhiều như trong Unix . Ngoài ra, các ống có tên không thể dễ dàng được gắn trong Windows, nếu có.

Cuối cùng, có sự tò mò nếu một khái niệm tốt có thể được đưa vào sử dụng tốt.


1
Bạn có nghĩa là như chuyển hướng đến một đường ống được đặt tên hoặc mailslot? Bạn có / sẵn sàng viết kết thúc nhận không?
ixe013

Vâng, giống như một ống hoặc mailslot được đặt tên. Tôi chưa có nhưng sẵn sàng viết kết thúc nhận.
n611x007

Câu trả lời:


8

Tôi không chắc tại sao bạn không muốn chuyển hướng đến một tập tin. Có hai phương pháp tôi sẽ cung cấp ở đây. Một phương pháp là chuyển hướng đến và đọc từ một tệp, hai là một bộ chương trình.


Đặt tên ống

Những gì tôi đã làm là viết hai chương trình cho .NET 4. Một chương trình gửi đầu ra đến một ống có tên, phần còn lại đọc từ ống này và hiển thị tới bàn điều khiển. Cách sử dụng khá đơn giản:

asdf.exe | NamedPipeServer.exe "APipeName"

Trong một cửa sổ giao diện điều khiển khác:

NamedPipeClient.exe "APipeName"

Thật không may, điều này chỉ có thể chuyển hướng stdout(hoặc stdin, hoặc kết hợp), chứ không phải stderrdo chính nó, do những hạn chế trong toán tử đường ống ( |) trong Dấu nhắc lệnh của Windows. Nếu bạn tìm ra cách gửi stderrqua toán tử đường ống, nó sẽ hoạt động. Ngoài ra, máy chủ có thể được sửa đổi để khởi chạy chương trình của bạn và đặc biệt chuyển hướng stderr. Nếu điều đó là cần thiết, hãy cho tôi biết trong một nhận xét (hoặc tự làm); không quá khó nếu bạn có kiến ​​thức về thư viện "Quy trình" C # và .NET.

Bạn có thể tải về máy chủmáy khách .

Nếu bạn đóng máy chủ sau khi kết nối, máy khách sẽ đóng ngay lập tức. Nếu bạn đóng máy khách sau khi kết nối, máy chủ sẽ đóng ngay khi bạn cố gửi thứ gì đó qua nó. Không thể kết nối lại một đường ống bị hỏng, chủ yếu là vì tôi không thể bận tâm làm điều gì đó quá phức tạp ngay bây giờ. Nó cũng giới hạn một khách hàng trên mỗi máy chủ .

Mã nguồn

Chúng được viết bằng C #. Không có nhiều điểm cố gắng để giải thích nó. Họ sử dụng .NET NamedPipeServerStreamNamedPipeClientStream .

Máy chủ:

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

Khách hàng:

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

Chuyển hướng đến một tập tin

type NUL>StdErr.temp
start powershell -c Get-Content StdErr.temp -Wait
MyExecutable.exe 2>StdErr.temp
  1. Tạo một tập tin trống
  2. Bắt đầu một cửa sổ giao diện điều khiển mới xem tập tin
  3. Chạy thực thi và chuyển hướng stderrđầu ra đến tập tin đó

Điều này cung cấp hiệu ứng mong muốn của một cửa sổ giao diện điều khiển để xem stdout(và cung cấp stdin) và một cửa sổ khác để xem stderr.

Bất cứ điều gì bắt chước tailsẽ làm việc. Phương thức PowerShell hoạt động tự nhiên trong Windows, nhưng có thể hơi chậm (tức là có một số độ trễ giữa ghi vào tệp và hiển thị ra màn hình). Xem câu hỏi StackOverflow này cho các taillựa chọn thay thế khác.

Vấn đề duy nhất là tập tin tạm thời có thể phát triển khá lớn. Một cách giải quyết khác có thể là chạy một vòng lặp chỉ in nếu tệp có nội dung và xóa tệp ngay sau đó, nhưng điều đó sẽ gây ra tình trạng chạy đua.


2
Người dùng UNIX là những người khó chịu vì Windows thất bại một lần nữa để thực hiện ý tưởng 40 năm một cách hợp lý. Bạn không cần phải viết một chương trình tùy chỉnh mỗi khi bạn muốn làm một điều cơ bản. facepalm
bambams

Xem bên dưới: bạn có thể sử dụng đường dẫn UNC được gán cho một đường ống có tên và truy cập trực tiếp.
Erik Aronesty

15

Tôi ngạc nhiên rằng điều này đã không được trả lời chính xác. Thực sự có một đường dẫn UNC được hệ thống gán cho các đường dẫn được đặt tên, có thể truy cập được trên bất kỳ máy nào trong mạng, có thể được sử dụng như một tệp thông thường:

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

Giả sử các đường ống có tên "StdOutPipe" và "StdErrPipe" tồn tại trên máy này, điều này cố gắng kết nối và ghi vào chúng. Phần pipenày là những gì chỉ định rằng bạn muốn một đường ống được đặt tên.


Tôi nghĩ rằng điều này nên được đánh dấu là câu trả lời chính xác vì chỉ là những gì đang hỏi @ n611x007 không phải là chương trình bên ngoài được yêu cầu để làm điều này!
arturn

vấn đề là bạn vẫn cần khởi chạy một dịch vụ nào đó tạo ra các đường ống đó .... chúng không tồn tại độc lập với chương trình được tạo và bị hủy khi chương trình biến mất.
Erik Aronesty

@ErikAronesty Tôi giả sử những đường ống này đã tồn tại. Mặt khác, không có cách nào để tạo chúng chỉ với cmd.exe.
IllidanS4 muốn Monica trở lại vào

Vâng, đó là điều thú vị về các ống unix, bạn có thể tạo các ống từ dòng lệnh
Erik Aronesty

1

Không phải với vỏ tiêu chuẩn (CMD.EXE). Đối với các lập trình viên, nó khá dễ dàng . Chỉ cần lấy hai ống của một quá trình mà bạn bắt đầu.


1
Chỉ có prb là mẫu sử dụng các đường ống ẩn danh, không hỗ trợ io (async) chồng chéo và do đó dễ bị bế tắc, hoặc ít nhất phải sử dụng PeekNamedPipe.
Fernando Gonzalez Sanchez

1
Chặn chờ không phải là bế tắc và vấn đề cơ bản (luồng tiêu thụ dữ liệu chặn luồng của nhà sản xuất tạo ra nó) không được giải quyết bằng I / O chồng chéo.
MSalters

Tôi có nghĩa là thế này: blog.msdn.com/b/oldnewthing/archive/2011/07/07/10183884.aspx , một ví dụ bế tắc.
Fernando Gonzalez Sanchez

1
@FernandoGonzalezSanchez: Khá nhiều vấn đề tương tự. Lưu ý rằng giải pháp được đề xuất (luồng bổ sung) vượt qua mọi nhu cầu về I / O không đồng bộ.
MSalters

1
Vâng, prb trong mẫu msd là cha mẹ bị kẹt chờ đợi mãi, trong hàm ReadFromPipe, dòng bSuccess = ReadFile (g_hChildStd_OUT_Rd, chBuf, BUFSIZE, & dwRead, NULL); sẽ đọc 70 byte lần đầu tiên và lần thứ 2 sẽ bị kẹt vĩnh viễn (PeekNamedPipe, bị thiếu, không chặn).
Fernando Gonzalez Sanchez

-1

Tùy chọn của bạn cho một ống dữ liệu Windows từ máy chủ đến cửa sổ định lượng máy khách ngay lập tức hoặc sau đó có thể được thỏa mãn với một ổ RAM nhỏ. Bộ nhớ tương tự được phân bổ cho dữ liệu, được ghi / đọc với tên giống như hệ thống tệp. Máy khách sẽ xóa tệp đã sử dụng và đợi tệp khác hoặc để tệp biến mất khi máy tính tắt.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.