– 很少,如果有的话,需要使用外部CLI(这通常值得努力 – PowerShell本机命令一起发挥得更好,不需要这样的功能).
– 不熟悉Bash的流程替换.
这个答案适合你,如果你:
– 经常使用外部CLI(无论是出于习惯还是由于缺乏(良好的)PowerShell本地替代方案),尤其是在编写脚本时.
– 习惯并了解Bash的流程替换可以做什么.
– 更新:既然Unix平台也支持PowerShell,这个功能越来越受到关注 – 请参阅 this feature request on GitHub,这表明PowerShell实现了类似于进程替换的功能.
在Unix世界中,在Bash / Ksh / Zsh中,进程替换是将命令输出视为一个临时文件,它可以自行清理;例如cat<(echo'hello'),其中cat将echo命令的输出视为包含命令输出的临时文件的路径. 虽然PowerShell本机命令并不真正需要这样的功能,但在处理外部CLI时它可以很方便. 在PowerShell中模拟该功能很麻烦,但如果您经常需要它,可能是值得的. 想象一个名为cf的函数,它接受一个脚本块,执行该块并将其输出写入temp.按需创建文件,并返回temp.文件的路径;例如.:
findstr.exe "Windows" (cf { Get-ChildItem c:\ }) # findstr sees the temp. file's path.
这是一个简单的例子,并没有很好地说明对这种功能的需求.也许更有说服力的情况是使用psftp.exe
进行SFTP传输:其批量(自动)使用需要提供包含所需命令的输入文件,而这些命令可以很容易地在运行中创建为字符串.
为了尽可能广泛地兼容外部工具,临时工.默认情况下,文件应使用UTF-8编码而不使用BOM(字节顺序标记),但如果需要,您可以使用-BOM请求UTF-8 BOM.
遗憾的是,无法直接模拟进程替换的自动清理方面,因此需要进行明确的清理调用;通过不带参数调用cf来执行清理:
>对于交互式使用,您可以通过向提示函数添加清理调用来自动执行清理,如下所示(提示函数返回提示字符串,但也可用于在每次显示提示时执行幕后命令,类似于Bash的$PROMPT_COMMAND变量);要获得任何交互式会话的可用性,请在PowerShell配置文件中添加以下以及cf的定义:
"function prompt { cf 4>`$null; $((get-item function:prompt).definition) }" | Invoke-Expression
>为了在脚本中使用,为了确保执行清理,使用cf的块 – 可能是整个脚本 – 需要包装在try / finally块中,其中调用不带参数的cf进行清理:
# Example try { # Pass the output from `Get-ChildItem` via a temporary file. findstr.exe "Windows" (cf { Get-ChildItem c:\ }) # cf() will reuse the existing temp. file for additional invocations. # Invoking it without parameters will delete the temp. file. } finally { cf # Clean up the temp. file. }
这是实现:高级函数ConvertTo-TempFile及其简洁的别名,cf:
注意:使用需要PSv3的New-Module通过动态模块定义函数可确保函数参数与传递的脚本块中引用的变量之间不存在可变冲突.
$null = New-Module { # Load as dynamic module # Define a succinct alias. set-alias cf ConvertTo-TempFile function ConvertTo-TempFile { [CmdletBinding(DefaultParameterSetName='Cleanup')] param( [Parameter(ParameterSetName='Standard',Mandatory=$true,Position=0)] [ScriptBlock] $ScriptBlock,[Parameter(ParameterSetName='Standard',Position=1)] [string] $LiteralPath,[Parameter(ParameterSetName='Standard')] [string] $Extension,[Parameter(ParameterSetName='Standard')] [switch] $BOM ) $prevFilePath = Test-Path variable:__cttfFilePath if ($PSCmdlet.ParameterSetName -eq 'Cleanup') { if ($prevFilePath) { Write-Verbose "Removing temp. file: $__cttfFilePath" Remove-Item -ErrorAction SilentlyContinue $__cttfFilePath Remove-Variable -Scope Script __cttfFilePath } else { Write-Verbose "Nothing to clean up." } } else { # script block specified if ($Extension -and $Extension -notlike '.*') { $Extension = ".$Extension" } if ($LiteralPath) { # Since we'll be using a .NET framework classes directly,# we must sync .NET's notion of the current dir. with PowerShell's. [Environment]::CurrentDirectory = $pwd if ([System.IO.Directory]::Exists($LiteralPath)) { $script:__cttfFilePath = [IO.Path]::Combine($LiteralPath,[IO.Path]::GetRandomFileName() + $Extension) Write-Verbose "Creating file with random name in specified folder: '$__cttfFilePath'." } else { # presumptive path to a *file* specified if (-not [System.IO.Directory]::Exists((Split-Path $LiteralPath))) { Throw "Output folder '$(Split-Path $LiteralPath)' must exist." } $script:__cttfFilePath = $LiteralPath Write-Verbose "Using explicitly specified file path: '$__cttfFilePath'." } } else { # Create temp. file in the user's temporary folder. if (-not $prevFilePath) { if ($Extension) { $script:__cttfFilePath = [IO.Path]::Combine([IO.Path]::GetTempPath(),[IO.Path]::GetRandomFileName() + $Extension) } else { $script:__cttfFilePath = [IO.Path]::GetTempFilename() } Write-Verbose "Creating temp. file: $__cttfFilePath" } else { Write-Verbose "Reusing temp. file: $__cttfFilePath" } } if (-not $BOM) { # UTF8 file *without* BOM # Note: Out-File,sadly,doesn't support creating UTF8-encoded files # *without a BOM*,so we must use the .NET framework. # [IO.StreamWriter] by default writes UTF-8 files without a BOM. $sw = New-Object IO.StreamWriter $__cttfFilePath try { . $ScriptBlock | Out-String -Stream | % { $sw.WriteLine($_) } } finally { $sw.Close() } } else { # UTF8 file *with* BOM . $ScriptBlock | Out-File -Encoding utf8 $__cttfFilePath } return $__cttfFilePath } } }