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

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

Powershell - format version number before outputting it

问题

以下是代码部分的翻译:

function ConvertFrom-FixedColumnTable {
  [CmdletBinding()]
  param(
    [Parameter(ValueFromPipeline)] [string] $InputObject
  )
  
  begin {
    Set-StrictMode -Version 1
    $lineNdx = 0
  }
  
  process {
    $lines = 
      if ($InputObject.Contains("`n")) { $InputObject.TrimEnd("`r", "`n") -split '\r?\n' }
      else { $InputObject }
    foreach ($line in $lines) {
      ++$lineNdx
      if ($lineNdx -eq 1) { 
        # 头部行
        $headerLine = $line 
      }
      elseif ($lineNdx -eq 2) { 
        # 分隔行
        # 获取字段开始的索引。
        $fieldStartIndices = [regex]::Matches($headerLine, '\b\S').Index
        # 计算字段长度。
        $fieldLengths = foreach ($i in 1..($fieldStartIndices.Count-1)) { 
          $fieldStartIndices[$i] - $fieldStartIndices[$i - 1] - 1
        }
        # 获取列名
        $colNames = foreach ($i in 0..($fieldStartIndices.Count-1)) {
          if ($i -eq $fieldStartIndices.Count-1) {
            $headerLine.Substring($fieldStartIndices[$i]).Trim()
          } else {
            $headerLine.Substring($fieldStartIndices[$i], $fieldLengths[$i]).Trim()
          }
        } 
      }
      else {
        # 数据行
        $oht = [ordered] @{} # 用于对象构造的有序帮助哈希表。
        $i = 0
        foreach ($colName in $colNames) {
          $oht[$colName] = 
            if ($fieldStartIndices[$i] -lt $line.Length) {
              if ($fieldLengths[$i] -and $fieldStartIndices[$i] + $fieldLengths[$i] -le $line.Length) {
                $line.Substring($fieldStartIndices[$i], $fieldLengths[$i]).Trim()
              }
              else {
                $line.Substring($fieldStartIndices[$i]).Trim()
              }
            }
          ++$i
        }
        # 将帮助哈希表转换为对象并输出它。
        [pscustomobject] $oht
      }
    }
  }
}

  
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new() 

(winget list --name "ourSoft") -match '^(\p{L}|-)' | # 过滤掉进度显示行
ConvertFrom-FixedColumnTable |    # 解析输出为对象
Select-Object -Property Name, Version | # 仅显示名称和版本
Sort-Object Name |                  # 按名称属性(列)排序
Format-Table                      # 以表格形式显示对象

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

function ModifyVersionNumber {	
	$VersionNumber = Select-Object -Property Version
	$CharArray = $VersionNumber.Split(".")
	$ModifiedCharArray = $CharArray[0] + "." + $CharArray[1] + "." + $CharArray[3] + "." + $CharArray[2]
	$ModifiedCharArray	
}
  
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new() 

(winget list --name "ourSoft") -match '^(\p{L}|-)' | # 过滤掉进度显示行
ConvertFrom-FixedColumnTable |    # 解析输出为对象 
ModifyVersionNumber | 
Select-Object -Property Name, Version | # 仅显示名称和版本
Sort-Object Name |                  # 按名称属性(列)排序
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:

function ConvertFrom-FixedColumnTable {
  [CmdletBinding()]
  param(
    [Parameter(ValueFromPipeline)] [string] $InputObject
  )
  
  begin {
    Set-StrictMode -Version 1
    $lineNdx = 0
  }
  
  process {
    $lines = 
      if ($InputObject.Contains("`n")) { $InputObject.TrimEnd("`r", "`n") -split '\r?\n' }
      else { $InputObject }
    foreach ($line in $lines) {
      ++$lineNdx
      if ($lineNdx -eq 1) { 
        # header line
        $headerLine = $line 
      }
      elseif ($lineNdx -eq 2) { 
        # separator line
        # Get the indices where the fields start.
        $fieldStartIndices = [regex]::Matches($headerLine, '\b\S').Index
        # Calculate the field lengths.
        $fieldLengths = foreach ($i in 1..($fieldStartIndices.Count-1)) { 
          $fieldStartIndices[$i] - $fieldStartIndices[$i - 1] - 1
        }
        # Get the column names
        $colNames = foreach ($i in 0..($fieldStartIndices.Count-1)) {
          if ($i -eq $fieldStartIndices.Count-1) {
            $headerLine.Substring($fieldStartIndices[$i]).Trim()
          } else {
            $headerLine.Substring($fieldStartIndices[$i], $fieldLengths[$i]).Trim()
          }
        } 
      }
      else {
        # data line
        $oht = [ordered] @{} # ordered helper hashtable for object constructions.
        $i = 0
        foreach ($colName in $colNames) {
          $oht[$colName] = 
            if ($fieldStartIndices[$i] -lt $line.Length) {
              if ($fieldLengths[$i] -and $fieldStartIndices[$i] + $fieldLengths[$i] -le $line.Length) {
                $line.Substring($fieldStartIndices[$i], $fieldLengths[$i]).Trim()
              }
              else {
                $line.Substring($fieldStartIndices[$i]).Trim()
              }
            }
          ++$i
        }
        # Convert the helper hashable to an object and output it.
        [pscustomobject] $oht
      }
    }
  }
  
}

  
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new() 

(winget list --name "ourSoft") -match '^(\p{L}|-)' | # filter out progress-display lines
ConvertFrom-FixedColumnTable |    # parse output into objects
Select-Object -Property Name, Version | # show only Name and Version
Sort-Object Name |                  # sort by the Name property (column)
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:

function ModifyVersionNumber {	
	$VersionNumber = Select-Object -Property Version
	$CharArray =$VersionNumber.Split(".")
	$ModifiedCharArray = $CharArray[0] + "." + $CharArray[1] + "." + $CharArray[3] + "." + $CharArray[2]
	$ModifiedCharArray	
}
  
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new() 

(winget list --name "ourSoft") -match '^(\p{L}|-)' | # filter out progress-display lines
ConvertFrom-FixedColumnTable |    # parse output into objects 
ModifyVersionNumber | 
Select-Object -Property Name, Version | # show only Name and Version
Sort-Object Name |                  # sort by the Name property (column)
Format-Table                      # display the objects in tabular format

答案1

得分: 2

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

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

给我返回的信息是:

无法对空值表达式调用方法
在行:3字符:5
+     $CharArray =$VersionNumber.Split(""."")
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

无法索引到空数组
在行:4字符:5
+     $ModifiedCharArray = $CharArray[0] + ""."" + $CharArray[1] + ""."" +  ...
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

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

function ModifyVersionNumber {
    param ([parameter(ValueFromPipeline = $true)]$Versions)
    process{
        foreach ($obj in $Versions) {
            $VersionNumber = $obj.Version;
            $CharArray =$VersionNumber.Split(""."")
            $ModifiedCharArray = $CharArray[0,1,3,2] -join '.'
            $obj.Version = $ModifiedCharArray;
            $obj;
        }
    }
}

另外,请考虑以下内容:$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:

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

gives me:

You cannot call a method on a null-valued expression.
At line:3 char:5
+     $CharArray =$VersionNumber.Split(".")
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

Cannot index into a null array.
At line:4 char:5
+     $ModifiedCharArray = $CharArray[0] + "." + $CharArray[1] + "." +  ...
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + 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:

function ModifyVersionNumber {
    param ([parameter(ValueFromPipeline = $true)]$Versions)
    process{
        foreach ($obj in $Versions) {
            $VersionNumber = $obj.Version;
            $CharArray =$VersionNumber.Split(".")
            $ModifiedCharArray = $CharArray[0,1,3,2] -join '.'
            $obj.Version = $ModifiedCharArray;
            $obj;
        }
    }
}

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

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

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

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

$version = '5.4.33676.0'
$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:

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

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

$version = '5.4.33676.0'
$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:

确定