增强管道的内容?
Enhancing the pipeline's content?
假设您有一个使用 7-zip 压缩文件的命令,该命令接受来自管道的值:
Function New-Archive {
[CmdletBinding()]
param (
[Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)][Alias('FullName')]
[string[]]$Files,
[string]$Archive='Archive.zip'
)
BEGIN {}
PROCESS {
Foreach ($File in $Files) {
& 7z a -tZIP $Archive $File
}
}
END {}
}
假设foo
目录有这些文件:a.txt、b.txt、c.txt
正在执行命令:
PS Foo> GCI | New-Archive
产生的输出类似于:
7-Zip [64] 9.20 Copyright (c) 1999-2010 Igor Pavlov 2010-11-18
Scanning
Updating archive .\files.zip
Compressing a.txt
Compressing b.txt
Compressing c.txt
Compressing files.zip
Everything is Ok
解析输出、捕获压缩结果并将其添加到管道中非常容易:
...
$output = & 7z a $Archive $File
#
# parse stdout; capture files that were compressed; convert to PsObject[]
#
$output = $output[7..($output.Length-4)]
$output | foreach {
$parts = $_ -split "\s+", 2
New-Object -Type PSObject -Property @{
Name = $parts[1]
}
}
问题:
- 管道应该包括原始内容(来自
GCI
)、修改后的内容(来自 7a
),还是两者都包括?
- 如果两者都有,这是怎么做到的?
- 结果文件 (Archive.zip) 的路径应该添加到管道中,还是由函数返回?
这有点主观,但我会说:
- 在失败的情况下重新抛出任何引发的异常(或使用 Write-Error)
- 除非有意义或被请求,否则不要产生输出
- 解析输出和 return 正确的对象,而不仅仅是来自您包装的可执行文件的输出字符串
在您的示例中,我可能会为 Archive.zip
添加一个 [Switch]$PassThru
参数和 return 一个 FileInfo 对象:Write-Output $(Get-Item $Archive)
(如果存在)
Updating archive .\files.zip ... Compressing files.zip
?检查你的函数在将 Archive.zip
添加到 Archive.zip
时是否有 case,这应该会引发警告,如复制自身。
关于管道 - 我认为你应该使用 -passthru
开关,如果开关存在,return 存档作为 Get-Item
结果(System.IO.FileInfo
对象),否则 return 无效。此外,如果您使用 -AsJob
标志,return 作业作为函数结果。
附带说明一下,如果您打算在 7zip 模块中使用存档,则需要指向它们的链接,可能作为通用文件的子类型,或者只是文件,并且由于 New-Archive
正在生成一个存档而不是一组,管道对于这个功能来说似乎是多余的。
总结:
- 在这种情况下,修改的内容还是作废。
- 没有"both".
- 返回一个
System.IO.FileInfo
对象将解决这两个目标。
- 考虑添加一个
-LogFile
参数来指示将来自 7zip 的文本数据放在何处。
假设您有一个使用 7-zip 压缩文件的命令,该命令接受来自管道的值:
Function New-Archive {
[CmdletBinding()]
param (
[Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)][Alias('FullName')]
[string[]]$Files,
[string]$Archive='Archive.zip'
)
BEGIN {}
PROCESS {
Foreach ($File in $Files) {
& 7z a -tZIP $Archive $File
}
}
END {}
}
假设foo
目录有这些文件:a.txt、b.txt、c.txt
正在执行命令:
PS Foo> GCI | New-Archive
产生的输出类似于:
7-Zip [64] 9.20 Copyright (c) 1999-2010 Igor Pavlov 2010-11-18
Scanning
Updating archive .\files.zip
Compressing a.txt
Compressing b.txt
Compressing c.txt
Compressing files.zip
Everything is Ok
解析输出、捕获压缩结果并将其添加到管道中非常容易:
...
$output = & 7z a $Archive $File
#
# parse stdout; capture files that were compressed; convert to PsObject[]
#
$output = $output[7..($output.Length-4)]
$output | foreach {
$parts = $_ -split "\s+", 2
New-Object -Type PSObject -Property @{
Name = $parts[1]
}
}
问题:
- 管道应该包括原始内容(来自
GCI
)、修改后的内容(来自7a
),还是两者都包括? - 如果两者都有,这是怎么做到的?
- 结果文件 (Archive.zip) 的路径应该添加到管道中,还是由函数返回?
这有点主观,但我会说:
- 在失败的情况下重新抛出任何引发的异常(或使用 Write-Error)
- 除非有意义或被请求,否则不要产生输出
- 解析输出和 return 正确的对象,而不仅仅是来自您包装的可执行文件的输出字符串
在您的示例中,我可能会为 Archive.zip
添加一个 [Switch]$PassThru
参数和 return 一个 FileInfo 对象:Write-Output $(Get-Item $Archive)
(如果存在)
Updating archive .\files.zip ... Compressing files.zip
?检查你的函数在将 Archive.zip
添加到 Archive.zip
时是否有 case,这应该会引发警告,如复制自身。
关于管道 - 我认为你应该使用 -passthru
开关,如果开关存在,return 存档作为 Get-Item
结果(System.IO.FileInfo
对象),否则 return 无效。此外,如果您使用 -AsJob
标志,return 作业作为函数结果。
附带说明一下,如果您打算在 7zip 模块中使用存档,则需要指向它们的链接,可能作为通用文件的子类型,或者只是文件,并且由于 New-Archive
正在生成一个存档而不是一组,管道对于这个功能来说似乎是多余的。
总结:
- 在这种情况下,修改的内容还是作废。
- 没有"both".
- 返回一个
System.IO.FileInfo
对象将解决这两个目标。 - 考虑添加一个
-LogFile
参数来指示将来自 7zip 的文本数据放在何处。