如何编写一个接受管道输入的PowerShell脚本?


75

我正在尝试编写可以获取管道输入的PowerShell脚本(并且有望这样做),但是尝试类似

ForEach-Object {
   # do something
}

在命令行中使用脚本时,实际上无法正常工作,如下所示:

1..20 | .\test.ps1

有办法吗?

注意:我了解函数和过滤器。这不是我想要的。

Answers:


42

这可行,可能还有其他方法可以做到:

foreach ($i in $input) {
    $i
}

17:12:42 PS> 1..20 | \ CMD-input.ps1
1
2
3
-剪断-
18
19
20

搜索“ powershell $ input变量”,您将找到更多信息和示例。
这里有几个:
PowerShell函数和过滤器PowerShell Pro!
(请参阅“使用PowerShell特殊变量“ $ input””一节)。
“脚本,函数和脚本块都可以访问$ input变量,该变量为传入管道中的元素提供枚举器。”

$ input «Dmitry的PowerBlog PowerShell以及其他
“ ...基本上是枚举器中的$ input,它提供对您拥有的管道的访问。”

对于PS命令行,而不是DOS命令行Windows命令处理器。


花费一些时间进行整理...只是为了使那些徘徊并阅读本文的人受益,DOS仍然在每个版本的Windows上都可用。64位或32位。
EBGreen

13
EBGreen(ntvdmWindows NT拥有的DOS VM)在64位系统上不再存在。cmd.exe不是DOS; 它是Windows命令处理器,除了黑色的灰色文本外,与DOS没有任何共同之处。
Joey

117

在v2中,您还可以接受管道输入(通过propertyName或byValue),添加参数别名等:

function Get-File{
    param(  
    [Parameter(
        Position=0, 
        Mandatory=$true, 
        ValueFromPipeline=$true,
        ValueFromPipelineByPropertyName=$true)
    ]
    [Alias('FullName')]
    [String[]]$FilePath
    ) 

    process {
       foreach($path in $FilePath)
       {
           Write-Host "file path is: $path"
       }
    }
}


# test ValueFromPipelineByPropertyName 
dir | Get-File

# test ValueFromPipeline (byValue) 

"D:\scripts\s1.txt","D:\scripts\s2.txt" | Get-File

 - or -

dir *.txt | foreach {$_.fullname} | Get-File

仍然是功能,而不是脚本。请参阅关于stackoverflow.com/questions/885349/…的评论。
乔伊

6
没关系,将函数体保存在脚本文件中并通过管道传递到脚本:。\ Get-File.ps1
谢伊·利维

7
实际上,您可以将param()块放在脚本的顶部,而无需声明脚本本地的函数。
Thomas S. Trias

24

您可以编写一个过滤器,该过滤器是此类函数的特例:

filter SquareIt([int]$num) { $_ * $_ }

或者您可以创建类似的功能,如下所示:

function SquareIt([int]$num) {
  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    $_ * $_
  }

  End {
    # Executes once after last pipeline object is processed
  }
}

上面的代码用作交互式函数定义,或者是否可以将脚本中的脚本点到全局会话(或其他脚本)中。但是,您的示例表明您需要一个脚本,因此此处使用的是可直接使用的脚本(无需打点):

  --- Contents of test.ps1 ---
  param([int]$num)

  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    $_ * $_
  }

  End {
    # Executes once after last pipeline object is processed
  }

在PowerShell V2中,这与“高级功能”有所不同,“高级功能”嵌入的功能具有与已编译cmdlet相同的参数绑定功能。有关差异的示例,请参见此博客文章。还要注意,在这种高级功能的情况下,您不使用$ _访问管道对象。使用高级功能,管道对象将绑定到参数,就像使用cmdlet一样。


我了解过滤器,但是我想将脚本用作管道中的元素,而不是脚本中定义的函数。谢谢,不过。
乔伊(Joey)

4
该过程块是您想要的。它的优点是不会阻塞管道。
JasonMArcher,2009年

如果指定参数,则应使用它。我以为它是某种参数原型的一部分,想知道为什么不使用它,或者是否可以代替它使用。浪费的周期。不过还是喜欢答案;)
Gerard ONeill

8

以下是使用管道输入的脚本/函数的最简单的示例。每个行为都与传递到“ echo” cmdlet的管道相同。

作为脚本:

#Echo-Pipe.ps1
  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    echo $_
  }

  End {
    # Executes once after last pipeline object is processed
  }
#Echo-Pipe2.ps1
foreach ($i in $input) {
    $i
}

作为功​​能:

Function Echo-Pipe {
  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    echo $_
  }

  End {
    # Executes once after last pipeline object is processed
  }
}

Function Echo-Pipe2 {
    foreach ($i in $input) {
        $i
    }
}

例如

PS > . theFileThatContainsTheFunctions.ps1 # This includes the functions into your session
PS > echo "hello world" | Echo-Pipe
hello world
PS > cat aFileWithThreeTestLines.txt | Echo-Pipe2
The first test line
The second test line
The third test line

为什么要重申基思已经在两年前给出的答案?
乔伊

他的回答包含以下问题:它不完全包含回答问题所必需的内容-平方是钝角。不需要函数参数,我们可以简单地使用$ _。“您可以编写一个过滤器,这是此类函数的特例”-没有语法意义,也不需要使用过滤器。
samthebest,2012年

这对我在ubuntu上起作用。上面的答案没有。
n.podbielski
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.