如果您满足以下条件,则
此答案不适合您:
-很少(如果有的话)需要使用外部CLI(通常值得努力-PowerShell本机命令可以更好地协同工作,并且不需要这种功能)。
-对Bash的流程替换不熟悉。如果您是这样的话,
这个答案就对您
有用:-经常使用外部CLI(无论是出于习惯还是由于缺少(好的)PowerShell本机替代品),尤其是在编写脚本时。
-习惯并欣赏Bash的流程替代可以做什么。
- 更新:现在Unix平台也支持PowerShell,此功能的重要性日益增加-请在GitHub上查看此功能请求,这表明PowerShell实施类似于进程替换的功能。
在Unix世界中,在Bash / Ksh / Zsh中,进程替换提供了将命令输出视为是一个临时文件,该文件将自己清除的功能。例如cat <(echo 'hello')
,在哪里cat
将echo
命令的输出视为包含命令输出的临时文件的路径。
尽管PowerShell本机命令实际上并不需要这种功能,但是在处理外部CLI时它很方便。
在PowerShell中模拟该功能很麻烦,但是如果您发现自己经常需要该功能,则可能值得这样做。
想象一个名为的函数cf
,该函数接受脚本块,执行该块并将其输出写入临时文件。文件按需创建,并返回温度。文件的路径;例如:
findstr.exe "Windows" (cf { Get-ChildItem c:\ }) # findstr sees the temp. file's path.
这是一个简单的示例,并未很好地说明对此类功能的需求。也许更令人信服的场景是使用psftp.exe
SFTP传输:批量(自动)使用需要提供包含所需命令的输入文件,而此类命令可以轻松地动态创建为字符串。
为了尽可能广泛地与外部实用程序兼容,温度。默认情况下,文件应该使用不带BOM的UTF-8编码(字节顺序标记),尽管您可以根据需要使用来请求UTF-8的BOM 。-BOM
不幸的是,不能直接模拟流程替换的自动清除方面,因此需要显式的清除调用。清理是通过cf
不带参数的调用来执行的:
对于交互式使用,您可以通过如下方式将清除调用添加到prompt
函数中来自动执行清除操作(该prompt
函数返回提示字符串,但也可以用于在每次显示提示时执行幕后命令,类似于Bash的$PROMPT_COMMAND
变量); 为了在任何交互式会话中保持可用性,请将以下内容以及cf
下面的定义添加到您的PowerShell配置文件中:
"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
:
注意:使用New-Module
,需要PSv3 +通过动态模块定义函数,以确保函数参数和传递的脚本块内引用的变量之间没有变量冲突。
$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
}
}
}
请注意,可以选择指定输出[文件]路径和/或文件扩展名。