Powershell – 输出版本号前格式化它

huangapple go评论140阅读模式
英文:

Powershell - format version number before outputting it

问题

以下是代码部分的翻译:

  1. function ConvertFrom-FixedColumnTable {
  2. [CmdletBinding()]
  3. param(
  4. [Parameter(ValueFromPipeline)] [string] $InputObject
  5. )
  6. begin {
  7. Set-StrictMode -Version 1
  8. $lineNdx = 0
  9. }
  10. process {
  11. $lines =
  12. if ($InputObject.Contains("`n")) { $InputObject.TrimEnd("`r", "`n") -split '\r?\n' }
  13. else { $InputObject }
  14. foreach ($line in $lines) {
  15. ++$lineNdx
  16. if ($lineNdx -eq 1) {
  17. # 头部行
  18. $headerLine = $line
  19. }
  20. elseif ($lineNdx -eq 2) {
  21. # 分隔行
  22. # 获取字段开始的索引。
  23. $fieldStartIndices = [regex]::Matches($headerLine, '\b\S').Index
  24. # 计算字段长度。
  25. $fieldLengths = foreach ($i in 1..($fieldStartIndices.Count-1)) {
  26. $fieldStartIndices[$i] - $fieldStartIndices[$i - 1] - 1
  27. }
  28. # 获取列名
  29. $colNames = foreach ($i in 0..($fieldStartIndices.Count-1)) {
  30. if ($i -eq $fieldStartIndices.Count-1) {
  31. $headerLine.Substring($fieldStartIndices[$i]).Trim()
  32. } else {
  33. $headerLine.Substring($fieldStartIndices[$i], $fieldLengths[$i]).Trim()
  34. }
  35. }
  36. }
  37. else {
  38. # 数据行
  39. $oht = [ordered] @{} # 用于对象构造的有序帮助哈希表。
  40. $i = 0
  41. foreach ($colName in $colNames) {
  42. $oht[$colName] =
  43. if ($fieldStartIndices[$i] -lt $line.Length) {
  44. if ($fieldLengths[$i] -and $fieldStartIndices[$i] + $fieldLengths[$i] -le $line.Length) {
  45. $line.Substring($fieldStartIndices[$i], $fieldLengths[$i]).Trim()
  46. }
  47. else {
  48. $line.Substring($fieldStartIndices[$i]).Trim()
  49. }
  50. }
  51. ++$i
  52. }
  53. # 将帮助哈希表转换为对象并输出它。
  54. [pscustomobject] $oht
  55. }
  56. }
  57. }
  58. }
  59. [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
  60. (winget list --name "ourSoft") -match '^(\p{L}|-)' | # 过滤掉进度显示行
  61. ConvertFrom-FixedColumnTable | # 解析输出为对象
  62. Select-Object -Property Name, Version | # 仅显示名称和版本
  63. Sort-Object Name | # 按名称属性(列)排序
  64. Format-Table # 以表格形式显示对象

以下是第二个代码部分的翻译:

  1. function ModifyVersionNumber {
  2. $VersionNumber = Select-Object -Property Version
  3. $CharArray = $VersionNumber.Split(".")
  4. $ModifiedCharArray = $CharArray[0] + "." + $CharArray[1] + "." + $CharArray[3] + "." + $CharArray[2]
  5. $ModifiedCharArray
  6. }
  7. [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
  8. (winget list --name "ourSoft") -match '^(\p{L}|-)' | # 过滤掉进度显示行
  9. ConvertFrom-FixedColumnTable | # 解析输出为对象
  10. ModifyVersionNumber |
  11. Select-Object -Property Name, Version | # 仅显示名称和版本
  12. Sort-Object Name | # 按名称属性(列)排序
  13. Format-Table # 以表格形式显示对象

希望这些翻译对你有所帮助。

英文:

I am trying to write a script, which will return a formatted version number.

However: due to winget outputting text, I have to first convert it to object, using the

Then I can get rid of the ID, which I have no use for and display only name and version.

Here's the code, taken from this answer:

  1. function ConvertFrom-FixedColumnTable {
  2. [CmdletBinding()]
  3. param(
  4. [Parameter(ValueFromPipeline)] [string] $InputObject
  5. )
  6. begin {
  7. Set-StrictMode -Version 1
  8. $lineNdx = 0
  9. }
  10. process {
  11. $lines =
  12. if ($InputObject.Contains("`n")) { $InputObject.TrimEnd("`r", "`n") -split '\r?\n' }
  13. else { $InputObject }
  14. foreach ($line in $lines) {
  15. ++$lineNdx
  16. if ($lineNdx -eq 1) {
  17. # header line
  18. $headerLine = $line
  19. }
  20. elseif ($lineNdx -eq 2) {
  21. # separator line
  22. # Get the indices where the fields start.
  23. $fieldStartIndices = [regex]::Matches($headerLine, '\b\S').Index
  24. # Calculate the field lengths.
  25. $fieldLengths = foreach ($i in 1..($fieldStartIndices.Count-1)) {
  26. $fieldStartIndices[$i] - $fieldStartIndices[$i - 1] - 1
  27. }
  28. # Get the column names
  29. $colNames = foreach ($i in 0..($fieldStartIndices.Count-1)) {
  30. if ($i -eq $fieldStartIndices.Count-1) {
  31. $headerLine.Substring($fieldStartIndices[$i]).Trim()
  32. } else {
  33. $headerLine.Substring($fieldStartIndices[$i], $fieldLengths[$i]).Trim()
  34. }
  35. }
  36. }
  37. else {
  38. # data line
  39. $oht = [ordered] @{} # ordered helper hashtable for object constructions.
  40. $i = 0
  41. foreach ($colName in $colNames) {
  42. $oht[$colName] =
  43. if ($fieldStartIndices[$i] -lt $line.Length) {
  44. if ($fieldLengths[$i] -and $fieldStartIndices[$i] + $fieldLengths[$i] -le $line.Length) {
  45. $line.Substring($fieldStartIndices[$i], $fieldLengths[$i]).Trim()
  46. }
  47. else {
  48. $line.Substring($fieldStartIndices[$i]).Trim()
  49. }
  50. }
  51. ++$i
  52. }
  53. # Convert the helper hashable to an object and output it.
  54. [pscustomobject] $oht
  55. }
  56. }
  57. }
  58. }
  59. [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
  60. (winget list --name "ourSoft") -match '^(\p{L}|-)' | # filter out progress-display lines
  61. ConvertFrom-FixedColumnTable | # parse output into objects
  62. Select-Object -Property Name, Version | # show only Name and Version
  63. Sort-Object Name | # sort by the Name property (column)
  64. Format-Table # display the objects in tabular format

I am trying to do the last step, which will return a version number different in what is stored in OS:

  • 5.4.33676.0 - stored number in OS

  • 5.4.0.33676 - what I want to return (part 3 and 4, divided by a dot, are swapped)

Is there any way to do that?

I am trying to write my own function for that, but it seems CharArray is not filling up + I don´t know how to make the piped output display the modified numbers instead of the former ones:

  1. function ModifyVersionNumber {
  2. $VersionNumber = Select-Object -Property Version
  3. $CharArray =$VersionNumber.Split(".")
  4. $ModifiedCharArray = $CharArray[0] + "." + $CharArray[1] + "." + $CharArray[3] + "." + $CharArray[2]
  5. $ModifiedCharArray
  6. }
  7. [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
  8. (winget list --name "ourSoft") -match '^(\p{L}|-)' | # filter out progress-display lines
  9. ConvertFrom-FixedColumnTable | # parse output into objects
  10. ModifyVersionNumber |
  11. Select-Object -Property Name, Version | # show only Name and Version
  12. Sort-Object Name | # sort by the Name property (column)
  13. Format-Table # display the objects in tabular format

答案1

得分: 2

如果我尝试运行您提供的函数来处理测试对象,我会得到为什么它不起作用的线索:

  1. $o = [pscustomobject]@{version = '5.4.0.33676'};
  2. $o | ModifyVersionNumber;

给我返回的信息是:

  1. 无法对空值表达式调用方法
  2. 在行:3字符:5
  3. + $CharArray =$VersionNumber.Split(""."")
  4. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  5. + CategoryInfo : InvalidOperation: (:) [], RuntimeException
  6. + FullyQualifiedErrorId : InvokeMethodOnNull
  7. 无法索引到空数组
  8. 在行:4字符:5
  9. + $ModifiedCharArray = $CharArray[0] + ""."" + $CharArray[1] + ""."" + ...
  10. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  11. + CategoryInfo : InvalidOperation: (:) [], RuntimeException
  12. + FullyQualifiedErrorId : NullArray

初始的 select-object 没有任何可操作的内容。我重新编写了该函数以从管道中获取参数,并且对于我的测试案例可以正常工作:

  1. function ModifyVersionNumber {
  2. param ([parameter(ValueFromPipeline = $true)]$Versions)
  3. process{
  4. foreach ($obj in $Versions) {
  5. $VersionNumber = $obj.Version;
  6. $CharArray =$VersionNumber.Split(""."")
  7. $ModifiedCharArray = $CharArray[0,1,3,2] -join '.'
  8. $obj.Version = $ModifiedCharArray;
  9. $obj;
  10. }
  11. }
  12. }

另外,请考虑以下内容:$ary = @(1,2,3,4); $ary[0,1,3,2] -join '.' 可以帮助大大减少您重新组装版本字符串的代码。

英文:

If I try to run your function as provided against a test object, I get a clue as to why it's not working:

  1. $o = [pscustomobject]@{version = '5.4.0.33676'};
  2. $o | ModifyVersionNumber;

gives me:

  1. You cannot call a method on a null-valued expression.
  2. At line:3 char:5
  3. + $CharArray =$VersionNumber.Split(".")
  4. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  5. + CategoryInfo : InvalidOperation: (:) [], RuntimeException
  6. + FullyQualifiedErrorId : InvokeMethodOnNull
  7. Cannot index into a null array.
  8. At line:4 char:5
  9. + $ModifiedCharArray = $CharArray[0] + "." + $CharArray[1] + "." + ...
  10. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  11. + CategoryInfo : InvalidOperation: (:) [], RuntimeException
  12. + FullyQualifiedErrorId : NullArray

That initial select-object doesn't have anything to operate on. I rewrote the function to take a parameter from the pipeline and it works for my test case:

  1. function ModifyVersionNumber {
  2. param ([parameter(ValueFromPipeline = $true)]$Versions)
  3. process{
  4. foreach ($obj in $Versions) {
  5. $VersionNumber = $obj.Version;
  6. $CharArray =$VersionNumber.Split(".")
  7. $ModifiedCharArray = $CharArray[0,1,3,2] -join '.'
  8. $obj.Version = $ModifiedCharArray;
  9. $obj;
  10. }
  11. }
  12. }

Also, for your consideration: $ary = @(1,2,3,4); $ary[0,1,3,2] -join '.' would help to significantly reduce the code where you're re-assembling the version string.

答案2

得分: 0

有多种方法可以处理这个问题。您可以将版本字符串拆分为其各个组件,然后手动按正确的顺序将它们组合在一起:

  1. $version = '5.4.33676.0'
  2. $major, $minor, $build, $revision = $version.Split('.')
  3. $version = $major, $minor, $revision, $build -join '.'

或者您可以使用 -replace 正则表达式运算符来替换最后两个组件:

  1. $version = '5.4.33676.0'
  2. $version = $version -split '\.(\d+)\.(\d+)$', '.$2.$1'
英文:

There's a number of ways to go about this. You could split the version string into its individual components and then manually join them together in the right order:

  1. $version = '5.4.33676.0'
  2. $major,$minor,$build,$revision = $version.Split('.')
  3. $version = $major,$minor,$revision,$build -join '.'

Or you could use the -replace regex operator to replace the two last components with eachother:

  1. $version = '5.4.33676.0'
  2. $version = $version -split '\.(\d+)\.(\d+)$', '.$2.$1'

huangapple
  • 本文由 发表于 2023年8月11日 00:09:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76877546.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定