将stdin引入Powershell流

时间:2016-07-29 21:13:56

标签: powershell batch-file

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

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

但是,我需要的是能够将文本从stdin传递到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

1 个答案:

答案 0 :(得分:7)

重写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通过$Input读取stdin输入,由this answer提供。

示例:

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

注意:

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

  • 因此,假设 $Input 枚举器,代表外部 stdin输入,我们可以肯定它逐个枚举输入文本行(作为字符串),所以我们只需选择感兴趣的行,这就是为Select-Object提供管道的原因已经足够了。

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

  • CAVEAT 当PowerShell与外界交谈时,涉及输入上的字符解码和输出上的重新编码

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

    • 否则,为痛苦的世界做好准备 - 详见下文。

解码/重新编码问题

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

    • 因此,使用正确识别的输入,如果您打印到控制台,事情看起来会很好,但如果您在文件中捕获输出,最终会得到一个OEM代码页编码的文件,这可能是不受欢迎的。

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

  • 如上所述,基于默认输入编码(也是OEM代码页,反映在PS中),正确识别的输入编码集不幸地限于以下内容为[Console]::InputEncoding;请记住:输入将在输出重新编码

    • ASCII 输入(输出时重新编码将默认保留此编码)
    • UTF-16 LE输入 BOM (这是PowerShell调用的Unicode,需要重新编码为输出上可能不同的内容)< / LI>
  • 默认情况下的代码页编码),但对 stdin 输入执行相同操作(如-Encoding <enc>中所反映的那样)将是非常重要的。

    • 例如,使用默认输入编码,如果您明确希望将输入解释为UTF-8(请再次注意,应用输出 Get-Content编码):
      $Input