windows 运行输入的可执行文件并将输出重定向到txt文件

6qftjkof  于 2023-11-21  发布在  Windows
关注(0)|答案(1)|浏览(167)

我试图将. exe文件的结果重定向到.txt文件中,但我在windows cmd中使用的命令

test.ext < input.txt > output.txt

字符串
didn not correctly show what input file input:

Enter top, an integer between 3 and 29 (including): Enter side, an integer between 2 and 20 (including): Enter 0 for left-tilt or 1 for right-tilt of the side: 
             ###
            #@#
           #@#
          ###

The number of characters on the perimeter:     10.
The number of characters in the interior:      2.
The number of characters of the parallelogram: 12.


在我的预期中,输出应该是这样的:

Enter top, an integer between 3 and 29 (including): 3
Enter side, an integer between 2 and 20 (including): 2
Enter 0 for left-tilt or 1 for right-tilt of the side: 0

             ###
            #@#
           #@#
          ###

The number of characters on the perimeter:     10.
The number of characters in the interior:      2.
The number of characters of the parallelogram: 12.


就像.exe文件显示我当我运行它。
有没有简单的方法来实现我想要的?

dsekswqp

dsekswqp1#

tl;dr

  • 行为归结为给定的可执行文件选择如何处理(默认情况下)* 交互式提示 *,特别是当它们的响应通过 * 标准输入 *(例如通过<重定向或通过管道输入(|))而不是通过 * 用户交互输入 * 提供时。
  • 结果是,获得不同行为的唯一方法是 * 修改可执行文件 *。
    两个方面发挥作用:
  • 一个交互式提示符的 message 是写到 stdout 还是直接写到终端 *,以及如果stdin被重定向,即如果响应将从stdin读取,是否打印消息 *。
  • 提示符的 * 响应 * 是否写入到 stdout,或者 * 直接写入到终端 *,或者 * 根本不写入 (如果响应是通过 * stdin 提供的)。
  • 理想情况下 *,如果stdin被重定向 *,您希望给定的可执行文件选择以下组合之一,基于以下设计选择:
    ***(a)*如果(默认情况下)交互式提示被认为是一个纯粹的交互式功能,与应用程序的(stdout) 输出 * 无关:
    • 既不打印 * 提示消息,也不打印从标准输入读取的值。
      ***(B)**如果应用程序希望生成更像交互式会话的 * 抄本 * 的输出,同时显示提示消息和响应:
  • 将提示消息和值从stdin * 打印到 stdout

不幸的是,您的可执行文件没有使用任何方法,并做出以下选择组合:

  • 它将提示消息写入stdout,而不打印(stdin提供的)响应
  • 由于提示消息本身没有尾随的换行符-假定响应应该在同一行上输入 * -没有打印响应(其中 * 确实 * 涉及尾随的换行符)意味着所有(连续的)提示消息出现在同一行上。

例如,* 批处理文件 * 会显示此行为**,您可以使用以下示例批处理文件进行验证:

@echo off

set /P V1="Prompt 1: "
set /P V2="Prompt 2: "
set /P V3="Prompt 3: "

echo Values provided: [%V1%] [%V2%] [%V3%]

字符串
标记为sample.cmd < input.txt > output.txtinput.txt中有3行输入,包含abc,您将在output.txt中看到以下输出:

Prompt 1: Prompt 2: Prompt 3: Values provided: [a] [b] [c]


也就是说,提示消息在没有换行符的情况下连接在一起,并且缺少响应。

PowerShell的 * 行为是特定于平台的,但a(b)解决方案是可能的任何一种方式
重要:以下内容仅适用于从 * 外部 * 通过其 CLIpowershell.exe用于Windows PowerShell,pwsh用于PowerShell(Core)7+)调用PowerShell代码,因为只有这样Read-Host才会从 * 重定向的stdin
读取响应。因此,在类似 Unix 的平台上,它也适用于通过shebang行在PowerShell中实现的可直接执行的shell脚本。

  • 在 * 类Unix* 平台**上,您可以通过常规的Read-Host调用获得所需的行为(b),如以下示例代码所示:
$values = 
   1..3 | ForEach-Object {
     Read-Host -Prompt "Prompt ${_}"
   }

 "Values provided: $($values.ForEach({ "[$_]" }))"

  • 不幸的是,在Windows上,提示消息 * 直接打印到控制台 *,因此 * 不是 * 通过标准输出重定向(>)捕获的;解决方法是 * 单独 * 打印提示消息,使用Write-Host及其-NoNewLine开关:
$values = 
   1..3 | ForEach-Object {
     Write-Host -NoNewLine "Prompt ${_}: "
     Read-Host
   }

 "Values provided: $($values.ForEach({ "[$_]" }))"


比如说,从cmd.exe转换为powershell -ExecutionPolicy Bypass -File sample.ps1 < input.txt > output.txt,在input.txt中有3行输入,包含abc,你会在output.txt中看到以下输出:

Prompt 1: a
Prompt 2: b
Prompt 3: c
Values provided: [a] [b] [c]


也就是说,这相当于行为(b):提示消息和stdin提供的响应都被打印到stdout[1],因此通过>捕获。

PowerShell还支持(a)解决方案,但需要额外的努力:

$values = 
  1..3 | ForEach-Object {
    # Print the prompt message only if stdin isn't redirected.
    if (-not [Console]::IsInputRedirected) {
      Write-Host -NoNewline "Prompt ${_}: "
    }
    # Use the [Console]::ReadLine() rather than Read-Host,
    # which *doesn't* echo a stdin-provided response.
    [Console]::ReadLine()
  }

"Values provided: $($values.ForEach({ "[$_]" }))"


使用与上面相同的示例调用,您现在可以得到:

Values provided: [a] [b] [c]


也就是说,这相当于行为(a):由于stdin重定向(<),提示消息和stdin提供的响应都没有被打印,因此不是>捕获的一部分。
注意事项:

  • 由于PowerShell是基于.NET构建的,这意味着编译后的.NET控制台应用程序可以实现相同的行为,如以下C#示例所示。
    C#实现(a)
using System;

static class Program {
  public static int Main(string[] args) {

    bool isStdInRedirected = Console.IsInputRedirected;
    int promptCount = 3;
    string[] values = new string[promptCount];

    for (int i = 1; i <= promptCount; ++i)
    {
      Console.Write(String.Format("Prompt {0}: ", i));
      values[i-1] = Console.ReadLine(); 
      if (isStdInRedirected) Console.WriteLine(values[i-1]);
    }

    Console.Write("Values provided:");
    for (int i = 1; i <= promptCount; ++i)
    {
      Console.Write(String.Format(" [{0}]", values[i-1]));
    }
    Console.WriteLine();

    return 0;
  }
}

(B)的C#实现

static class Program {
  public static int Main(string[] args) {

    bool isStdInRedirected = Console.IsInputRedirected;
    int promptCount = 3;
    string[] values = new string[promptCount];

    for (int i = 1; i <= promptCount; ++i)
    {
      if (!isStdInRedirected) Console.Write(String.Format("Prompt {0}: ", i));
      values[i-1] = Console.ReadLine(); 
    }

    Console.Write("Values provided:");
    for (int i = 1; i <= promptCount; ++i)
    {
      Console.Write(String.Format(" [{0}]", values[i-1]));
    }
    Console.WriteLine();

    return 0;
  }
}


[1]也许令人惊讶的是,Write-Host也打印到标准输出,即使PowerShell-* 内部 * 它被设计为 * 绕过 * PowerShell的类似 * 成功 * output stream
事实上-不幸的是-默认情况下,PowerShell的所有 *(六个!)输出流都Map到外部调用者看到的标准输出流-参见GitHub issue #7989

相关问题