【问题标题】:Getting stdin into the Powershell stream让标准输入进入 Powershell 流
【发布时间】:2016-12-04 16:31:26
【问题描述】:

当在命令行中指定文件名时,以下脚本运行良好。

尾巴.bat
@echo off
set "COUNT=%1"
set "COUNT=%COUNT:-=%"
set "FILENAME=%~2"
powershell "Get-Content %FILENAME% -Last %COUNT%"

但是,我需要能够将文本从标准输入传送到Get-Content。我想编写以下内容来获取分配给项目的最后三个 Subversion 标记。我该怎么做才能让Get-Content 的源成为标准输入?

svn ls svn://ahost/arepo/aproject/tags | call tail.bat -3

注意:我不允许从外部安装任何有用的工具,例如 tail。必须使用机器上已有的程序来完成。

更新:

@mklement0 提供了答案。从那开始,我添加了代码以使用默认的 COUNT 值 10(如果未提供)。这符合 UNIX/Linux 的方式。

@echo off

SET "COUNT=%~1"
IF "%COUNT:~0,1%" == "-" (
    SET "COUNT=%COUNT:~1%"
    SHIFT
) ELSE (
    SET "COUNT=10"
)
SET "FILENAME=%~1"

if "%FILENAME%" == "" (
    powershell -noprofile -command "$Input | Select-Object -Last %COUNT%"
) else (
    powershell -noprofile -command "Get-Content \"%FILENAME%\" -Last %COUNT%"
)

EXIT /B

【问题讨论】:

    标签: powershell batch-file


    【解决方案1】:

    改写tail.bat如下:

    @echo off
    
    set "COUNT=%1"
    set "COUNT=%COUNT:-=%"
    set "FILENAME=%~2"
    
    if "%FILENAME%"=="" (
      powershell -noprofile -command "$Input | Select-Object -Last %COUNT%"
    ) else (
      powershell -noprofile -command "Get-Content \"%FILENAME%\" -Last %COUNT%"
    )
    

    如果没有传递文件名参数,这将使 PowerShell CLI 通过 automatic $input variable 读取标准输入,由 this answer 提供。

    例子:

    C:> (echo one & echo two & echo three) | tail.bat -2
    two
    three
    

    注意:

    • 虽然 PowerShell 通常通过管道发送并输出任何类型的对象,但它与外部世界的接口总是涉及字符串

    • 因此,鉴于 $Input 是一个 枚举器,它代表 外部 标准输入输入,我们可以确定它枚举输入文本行(作为字符串)一一对应,所以我们只需要选择感兴趣的行,这就是为什么管道到Select-Object就足够了。

    • 相比之下,在 PowerShell 中按名称读取 文件 需要 Get-Content(顺便提一下,它还会通过管道一一发送输入文件的行,除非您还指定 -Raw) ;因为Get-Content 具有内置的tail 功能,通过参数-Tail(及其别名-Last),这就是这里所需要的。

    • CAVEAT:当 PowerShell 与外界对话时,涉及输入字符解码和输出重新编码

      • 如果您只处理 ASCII 编码的输入(单字节字符,代码点介于 0 到 127 之间),您不必担心。

      • 否则,为痛苦的世界做好准备 - 详情请参阅下文。


    字符解码/重新编码问题:

    • 假设 PowerShell 识别您的 输入 编码(见下文),输出 编码总是 控制台窗口 em> 分配的编码是;默认情况下,不幸的是,这是 OEM 代码页(例如,美国英语系统上的“DOS”代码页 CP437),在 PS 中反映为[Console]::OutputEncoding

    • 因此,在正确识别输入的情况下,如果您打印到 console,一切看起来都不错,但如果您将输出捕获到 file,您将结束加上一个 OEM 代码页编码的文件,这可能是不受欢迎的。

    • 如果可行,您可以从根本上设置控制台窗口以使用您选择的代码页(输入输出编码)(使用chcp),但尝试不幸的是,更改脚本中的编码 ad-hoc 是不可行的。
      请注意,使用 UTF-8 - 代码页 65001 - 仅在您将控制台窗口配置为使用 TT (TrueType) 字体之一时才有效。

    • 如上所述,不幸的是,正确识别的 input 编码集仅限于以下,基于默认输入编码(这也是 OEM 代码页,在 PS 中反映为 @987654339 @; 记住:输入将在输出重新编码):

      • ASCII 输入(在输出上重新编码将默认保留此编码)
      • UTF-16 LE 输入带有一个 BOM(这是 PowerShell 所称的 Unicode,可能会重新编码为输出可能不同的内容)
    • 可以通过将-Encoding <enc> 添加到Get-Content 调用(默认情况下需要Windows 默认代码页编码)来硬编码预期的输入 编码,但是对 stdin 输入做同样的事情(如$Input 所反映的那样)将是非常重要的。

      • 例如,使用默认输入编码,如果您明确希望将输入解释为 UTF-8(再次注意,在 输出 上应用了[Console]::OutputEncoding 编码):
        @987654345 @

    【讨论】:

    • 谢谢。我正在学习如何处理$InputSelect-Object vs. Get-Content
    • 感谢您的补充。我熟悉编码问题,因为在 Unicode 存在之前,我正在让 DOS 和 Windows 程序在日本机器上运行。很有趣。
    猜你喜欢
    • 1970-01-01
    • 2011-02-15
    • 2017-07-21
    • 1970-01-01
    • 2015-11-05
    • 1970-01-01
    • 2010-12-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多