当快速连续调用时,将剪贴板设置为只记住最后一个值



我正在尝试创建一个powershell片段,该片段将多行管道输入的第一列复制到剪贴板。

预期用途为:kubectl get pods | copyfirst
这应该允许我在剪贴板中拥有所有pod名称,并使用Win+V选择我需要的单个pod名称。

到目前为止,我拥有的是:

function copyfirst {
[CmdletBinding()]Param([Parameter(ValueFromPipeline)]$Param)
process {
$Param.Split(" ")[0] | Set-Clipboard
}
}

问题是,这只会将最后一个条目复制到剪贴板,而其他所有条目都会被忽略。

如果我将Set-Clipboard更改为其他命令,它将按预期工作。例如,echo输出所有pod名称,而不仅仅是最后一个。

我认为mklement0的答案是正确的,我个人并不知道Win+V剪贴板的功能。所以,你是对的,因为当它快速连续地完成时,似乎无法捕捉历史。

通过添加Start-Sleep,它可以很好地工作:

function copyfirst {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline)]
[object[]] $Param
)
process {
$Param.Split(' ')[0] | Set-Clipboard
Start-Sleep -Milliseconds 250
}
}
@'
string1 string4
string2 string5
string3 string6
'@ -split 'r?n' | copyfirst

它应该捕获string1string2string3

调整睡眠计时器,直到它不太慢,它可以捕捉所有内容。


经过一些测试,似乎Start-Sleep可以减少到-Milliseconds 250,低于这个值会产生不一致的结果。

注意:

  • 此答案显示如何将所有输入行中的第一个空格分隔字段复制为单个剪贴板条目。

  • 事实证明,OP的意图是将每个这样的字段分别复制到剪贴板,以创建一系列可以通过Windows 10剪贴板历史记录功能(WinKey+V(调用的条目,Santiago Squarzon的有用答案为其提供了解决方案。


要从所有输入对象复制数据,必须在process块中收集数据,并在处理完所有输入对象后将该集合复制到end块中的剪贴板:

function copyfirst {
[CmdletBinding()]Param([Parameter(ValueFromPipeline)]$Param)
begin {
# Initialize the collection (list) that will collect data.
$coll = [System.Collections.Generic.List[object]]::new()
}
process {
# Add to the collection.
$coll.Add($Param.Split(" ")[0])
}
end {
# Copy the collection to the clipboard.
# More efficient alternative:
#    Set-Clipboard $coll
$coll | Set-Clipboard
}
}

对于每个输入对象,process块被称为,并且Set-Clipboard总是替换剪贴板上以前的内容,这解释了为什么只有最后一个数据项被放置在那里。

请注意,外部程序的stdout输出是通过管道逐行传递的。


请注意,在您的情况下,有一个更简单的替代方案,使用简单(非高级(功能和自动$input变量:

function copyfirst {
$input | ForEach-Object { $_.Split(' ')[0] } | Set-Clipboard
}

这种方法的潜在缺点是失去了管道的方面(逐个处理(,因为简单函数的主体就像一个隐式end块,PowerShell在其中通过$input提供收集的前端输入对象。

然而,在这种情况下,这并不重要,因为无论如何都需要收集所有数据。

您可以使用.ForEach()数组方法而不是ForEach-Objectcmdlet来稍微加快操作速度,尽管我怀疑在这种情况下这是否重要。

我发现,当set-clipboard在同一过程中使用时,剪贴板会被覆盖。有一个-append,但它会附加到最后一个剪贴板,而不是添加到剪贴板列表中。

我最终所做的是构建一个命令,并在一个新的过程中为数组中的每个项目执行它(这很慢!(如下:

function copyfirst {
[CmdletBinding()]Param([Parameter(ValueFromPipeline)]$Param)

foreach($line in $Param.split("`n")){
$podName = $line.split(" ")[0]
if ($podName -ne "NAME"){
$scriptBlock = "Write-Output `"$podName`"  | Set-Clipboard; Start-sleep -milliseconds 1"
Powershell $scriptBlock
}
}
}

"NAME READY STATUS RESTARTS AGE 
redis-fd794cd65-k9mhp 1/1 Running 0 3h15m
website-restrictor-c6f5bbd56-fxb59 1/1 Running 0 3h15" | copyfirst

这将导致使用Windows Key + V时看到的单个剪贴板条目

注意Start-sleep -milliseconds 1,这是因为在非常快速地执行set-clipboardcmdlet时出现了一些奇怪的行为,在这里注意到-https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/set-clipboard?view=powershell-7.1#钞票

最新更新