我正在寻找可与 Python 交互式 shell 的“_”变量相媲美的功能。在 PowerShell 我想要这样的东西:
> Get-Something # this returns an object and display it to the output.
# Now I want to assign that object to some variable
> $anObj = ???
我正在寻找可与 Python 交互式 shell 的“_”变量相媲美的功能。在 PowerShell 我想要这样的东西:
> Get-Something # this returns an object and display it to the output.
# Now I want to assign that object to some variable
> $anObj = ???
不,没有这样的自动变量。
你所要做的:
$output = Get-Something
$output
$anObj = $output
获得行为
如前所述,没有对此的内置支持,但这是一个简单但次优的 PSv3+自定义解决方案:
笔记:
有关适当但重要的解决方案,请参阅BartekB 的有用答案。
GitHub 功能请求 #7853要求将此功能构建到未来的 PowerShell Core 版本中(撰写本文时的当前版本是 PowerShell (Core) 7.2)。
将以下内容添加到您的$PROFILE
文件中:
# Store previous command's output in $__
$PSDefaultParameterValues['Out-Default:OutVariable'] = '__'
命名变量的名称$__
(例如本例中的(2 个下划线))由您决定,但请注意名称冲突,尤其是与$_
在许多上下文中表示手头输入对象的自动变量的名称冲突。
这将$__
通过 PowerShell 全局预设参数默认值的能力来捕获交互式会话中最近执行的PowerShell命令 [产生终端输出]的终端绑定Get-Help about_Parameters_Default_Values
输出 - 请参阅.
-OutVariable
是一个通用参数,旨在将 cmdlet/高级函数的输出对象收集到变量中,并且上述定义将此参数隐式应用于所有Out-Default
调用,每当 PowerShell 向终端输出某些内容时,都会在后台调用该参数 - 但是,请注意下面提到的例外情况。
注意事项:
如果需要,请使用$saved = $__.Clone()
保存捕获的输出以供以后使用,因为它$__
会在每个命令上重新分配(当然,如果您提前知道要保留命令的输出,请使用以开头的分配:)$saved = <command>
。
$saved = $__
不起作用,因为这$saved
指向与 相同的[ArrayList]
实例$__
,该实例将在下一个命令中重新填充。在以下情况下不会捕获输出:
来自外部程序的输出,例如git
,因为根据设计 PowerShell 将来自外部程序的输出流直接传递到终端(除非它们被重定向或捕获),因此不会调用Out-Default
. 最简单的解决方法是通过管道传输Write-Output
(类似于*>&1
通过 PowerShell 流显式路由的方法不起作用);例如:
whoami.exe | Write-Output # $__ is now populated
显式调用格式化 cmdlet的命令的输出- Format-Custom
、Format-Hex
、Format-List
、Format-Table
或Format-Wide
.
$PSDefaultParameterValues['Format-*:OutVariable'] = '__'
,但不幸的是,这会收集格式化对象(指令)而不是 中的原始数据,$__
这是不希望的。一个不令人满意的解决方法是在不同的变量中捕获Format-*
输出,这不仅需要您考虑需要定位哪个变量,而且您仍然只能看到格式化对象而不是数据,而且由于cmdlet 甚至在幕后都涉及如果您没有明确使用它们,那么没有调用的命令的输出将被捕获两次- 一次作为数据, in ,另一次作为格式化对象,在另一个变量中。Format-*
Format-*
$__
由于设计怪癖,$__
总是包含一个数组列表(类型[System.Collections.ArrayList]
),即使前面的命令只输出一个对象。如有疑问,请使用$($__)
(或$__[0]
) 来获取单个输出对象。
注意产生非常大的输出集的命令,因为$__
会将它们收集在内存中。
$__
只会捕获输出到终端的对象- 就像_
在 Python 中一样;一个不产生输出的命令或$null
/ 一个 s 的数组会保留$null
任何先前的$__
值不变。
您还可以使用 OutVariable 参数打印命令的结果并捕获输出对象,然后使用 $anObj 显示变量内容。
Get-Something -OutVariable anObj
最后一个需要大部分工作的选项,但 IMO 为您提供了您所要求的:创建将覆盖 Out-Default 的代理(如果您不使用其他内容,则始终在管道末尾隐式调用该代理)。
Jeffrey Snover 在一次 PowerShell Deep Dives(我认为这是第一次)中对它进行了介绍 - 你可以在Dmitry Sotnikov 博客上找到他使用的脚本(包括上面提到的默认) 。您还可以观看其中的视频以了解整个概念。
不完全是。有 $_ 自动值,其中包含管道中的当前对象。
管道是将结果从一个 cmdlet 传递到下一个的常用方法,并且 cmdlet 被设置为接受来自管道的参数或管道中对象的属性,从而使“最后结果”变量的使用无关紧要。
仍然有些情况确实需要对“管道”对象的特定引用,对于那些有 $_ 自动值。
下面是它的用法示例:使用 Where-Object Cmdlet,这里是 powershell 的自动变量列表:第 4 章。PowerShell 自动变量
powershell 中的脚本编写需要与 Python 中的编程不同的风格(就像 Python 需要与 C++ 不同的风格一样。)
Powershell 的构建使得管道被广泛使用,如果您想将管道分解为更程序化的逐步结构,您需要将结果保存在命名变量中,而不是自动变量中。
用“r”(Invoke-History 的别名)调用最后一个命令并将其包裹在括号()中以首先执行它怎么样?
是的,这会重新运行最后一个命令,但在我的用例中,这是迄今为止最精简的解决方案,尤其是当我没有意识到我首先需要最后一个命令输出的时候。
它还保持对象结构完整。
PS C:\Users\user> Get-NetAdapter -InterfaceIndex 3 | Where {$_.State -match "2"}
Name InterfaceDescription ifIndex Status MacAddress LinkSpeed
---- -------------------- ------- ------ ---------- ---------
Ethernet Intel(R) Ethernet Connection I217-LM 3 Up XX-XX-XX-XX-XX-XX 100 Mbps
PS C:\Users\user> (r) |where {$_.LinkSpeed -eq "100 Mbps"}
Get-NetAdapter -InterfaceIndex 3 | Where {$_.State -match "2"}
Name InterfaceDescription ifIndex Status MacAddress LinkSpeed
---- -------------------- ------- ------ ---------- ---------
Ethernet Intel(R) Ethernet Connection I217-LM 3 Up XX-XX-XX-XX-XX-XX 100 Mbps
PS C:\Users\user> (r).MacAddress
Get-NetAdapter -InterfaceIndex 3 | Where {$_.State -match "2"}
XX-XX-XX-XX-XX-XX
对于我的特定用例,我从 PowerShell 运行批处理文件,我想实时打印该批处理文件的输出并将输出保存到变量中。我可以通过将呼叫操作员的输出传送到Tee-Object
:
$args = @('-r', '-a');
& "C:\myFile.bat" $args | Tee-Object -Variable output;
$output | Set-Clipboard;
第一个命令为批处理文件设置我的参数。第二个命令使用带有我的参数的调用运算符运行批处理文件,并将输出通过管道传递给Tee-Object
命令,该命令实时打印调用运算符的输出,但还将所有信息保存到一个名为output的新变量中。最后一个命令只是将 的内容复制$output
到剪贴板。
Tee-Object
还允许将输出保存到文件(Unicode 编码),如果我需要保存到文件和变量(除了打印到控制台),我可以将多个调用链接到Tee-Object
一个管道中。有关更多信息,请参阅此链接:
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/tee-object
这是来自 Windows Powershell in Action。在你的 $profile 中获取它,它使 $last 包含最后一个命令的输出。它还将通过在 la zsh 中键入目录名称来更改目录,或者通过键入网站的 url 在浏览器中访问网站。它创建了一个 Out-Default 函数,该函数覆盖 Out-Default cmdlet 并调用它。我添加了“start-process $__command”行,所以去一个网站可以在 osx 中工作。
这是相当具有侵略性的。后来我出于某种原因在我的 $profile 中禁用了它。
#
# Wrapping an exiting command with a function that uses
# steppable pipelines to "remote-control" the wrapped command.
function Out-Default
{
[CmdletBinding(ConfirmImpact="Medium")]
param(
[Parameter(ValueFromPipeline=$true)]
[System.Management.Automation.PSObject] $InputObject
)
begin {
$wrappedCmdlet = $ExecutionContext.InvokeCommand.GetCmdlet(
"Out-Default")
$sb = { & $wrappedCmdlet @PSBoundParameters }
$__sp = $sb.GetSteppablePipeline()
$__sp.Begin($pscmdlet)
}
process {
$do_process = $true
if ($_ -is [System.Management.Automation.ErrorRecord]) {
if ($_.Exception -is
[System.Management.Automation.CommandNotFoundException]) {
$__command = $_.Exception.CommandName
if (test-path -path $__command -pathtype container) {
set-location $__command
$do_process = $false
}
elseif ($__command -match '^http://|\.(com|org|net|edu)$') {
if ($matches[0] -ne "http://") {$__command = "HTTP://" +
$__command }
# [diagnostics.process]::Start($__command)
start-process $__command
$do_process = $false
}
}
}
if ($do_process) {
$global:LAST = $_;
$__sp.Process($_)
}
}
end {
$__sp.End()
}
}
一种对我有用的方法是将命令的输出Select-Object
作为传递来处理。例如,我有一个控制台 EXE,它输出详细输出到stderr
和有意义的输出到stdout
,我只想捕获最后一行。
$UtilityPath = ""
(UpdateUtility.exe $ArgList 2>&1) | % {
If ($_ -Is [System.Management.Automation.ErrorRecord]) {
$_.Exception.Message
}
Else {
$_
$UtilityPath = $_
}
}
调用此脚本的方式,在 PowerShell 的Error
输出流上输出被认为是一个硬错误,这与 PowerShell 获取外部应用程序的stderr
输出并将其转换为Error
输出的方式不符。这种包装输出的方法使我能够控制它如何通过,以及捕获stdout
我想要的行。在我看来,这将是一种相当灵活的方法,可以让您拦截输出并在输出通过时对其执行任何您想做的事情。例如:
$CommandOutput = ""
SomeOtherCommand | % {
$CommandOutput += "$_`r`n"
$_
}
使用模块 PowerShellCookbook 并将对 Add-ObjectCollector 的调用添加到您的启动脚本
您可以尝试“ (Get-History)[-1].CommandLine ”。