如何在使用PowerShell向csv文件添加新列时指定列位置

suzh9iv8  于 2022-12-29  发布在  Shell
关注(0)|答案(3)|浏览(147)

向现有csv文件添加新列时,如何指定列位置?
我想添加新列作为第二列(不是在默认的末尾)。
第一列总是相同的,但是其他列对于每个文件可以不同(因此预先不知道存在哪些列(名称和顺序)(除了第一列,其总是包含名称))。
据我所知,Add-Member没有位置参数。

    • 样品代码:**
$csv = Import-Csv -Path "attendees.csv" -Delimiter ';' 

foreach ($row in $csv)
{
    $row | Add-Member -'GUID' -Value (New-Guid).Guid -MemberType NoteProperty 
}

$csv | Export-Csv new_attendees.csv' -NoTypeInformation
k97glaaz

k97glaaz1#

以防您事先不知道列名。
Select-Objectcalculated property配合使用:

$csv = Import-Csv -Path "attendees.csv" -Delimiter ';' 
$Properties = [Collections.Generic.List[Object]]$csv[0].psobject.properties.name
$Properties.Insert(1, @{ n='Guid'; e={ New-Guid } }) # insert at column #1
$csv |Select-Object -Property $Properties |Export-Csv new_attendees.csv' -NoTypeInformation
    • 解释:**(2022年11月12日更新)
  • 每个对象PowerShell都有一个隐藏的PSObject属性,您可以在其中动态访问有关该属性的信息,例如其名称。
  • 使用PowerShell Member-Access enumeration功能将所有psobject.properties.name作为标量字符串数组列出。
  • 我只使用第一个对象$csv[0]来确定属性(列)名称,因为我不想阻塞PowerShell管道并继续支持一次一个的处理。换句话说,我假定以下对象具有统一的属性名称。任何编写良好的PowerShell cmdlet都遵循强烈鼓励的开发准则来实现管道的中间
  • 由于隐式的. Net转换,将PowerShell数组(属性名)类型转换为Collections.Generic.List[Object]类型非常容易
  • 它恰好有一个List<T>.Insert(Int32, T)方法,允许您在某个位置插入一个项(在本例中为object)(在本例中为:1
  • 请注意,此方法是 * 从零开始的 *
  • Select-Object cmdlet的-Property参数不仅支持属性名称的有序列表,还支持calculated properties,此处使用calculated properties创建完整的属性及其名称、值(表达式),格式为:

x1米10英寸1x

5rgfhyps

5rgfhyps2#

我不认为有一个简单的方法来插入一个属性到一个对象的地方在一个特定的索引,但这里有一个快速的概念证明,我敲出来创建一个新的对象的基础上,原来的...
它可能需要一些错误处理,也许还需要一些参数属性来支持管道,但它基本上是工作的...

function Insert-NoteProperty
{

    param(
        [pscustomobject] $InputObject,
        [string] $Name,
        [object] $Value,
        [int] $Index
    )

    $properties = @($InputObject.psobject.Properties);

    $result = [ordered] @{};

    # append the properties before the index
    for( $i = 0; $i -lt $Index; $i++ )
    {
        $result.Add($properties[$i].Name, $properties[$i].Value);
    }

    # append the new property
    $result.Add($Name, $Value);

    # append the properties after the index
    for( $i = $Index; $i -lt $properties.Length; $i++ )
    {
        $result.Add($properties[$i].Name, $properties[$i].Value);
    }

    return [pscustomobject] $result;

}

示例:

$original = [pscustomobject] [ordered] @{ "aaa"="bbb"; "ccc"="ddd" }

$original
# aaa ccc
# --- ---
# bbb ddd

$updated = Insert-NoteProperty `
    -InputObject $original `
    -Name        "new" `
    -Value       "value" `
    -Index       1;

$updated
# aaa new   ccc
# --- ---   ---
# bbb value ddd

您可以按如下所示将其用于csv文件:

$csv = @"
aaa,ccc
bbb,ddd
"@

$data = $csv | ConvertFrom-Csv;

$newdata = $data | foreach-object {
    Insert-NoteProperty `
        -InputObject $_ `
        -Name        "new" `
        -Value       "value" `
        -Index       1
}

$newcsv = $newdata | ConvertTo-Csv

$newcsv
# "aaa","new","ccc"
# "bbb","value","ddd"
v64noz0r

v64noz0r3#

Add-Member不允许你指定在哪个位置添加属性到一个对象。所以你必须建立一个新的对象,在那里你可以控制属性的位置,例如:

$newObjects = @(
    foreach ($row in $csv){
        $attrsHt = [ordered]@{
            [propertyName]=[propertyValue]
            Guid=([guid]::NewGuid()).guid
            [propertyName]=[propertyValue]
            [propertyName]=[propertyValue]
        }
        New-Object -TypeName psobject -Property $attrsht
    }
)

或者你可以使用select-object来改变输出的顺序:

foreach ($row in $csv)
{
    $row | Add-Member -Name 'GUID' -Value (New-Guid).Guid -MemberType NoteProperty 
}

$csv | select-object [propertyName],Guid,[propertyName],[propertyName] | export-csv new_attendees.csv' -NoTypeInformation

由于propertyNames是未知/动态的,您可以执行以下操作:

#Get the csv header and split by delimiter to get array of property names
[System.Collections.ArrayList]$csvHeader = (get-content [path])[0] -split ","

#Insert Guid at 2nd Position
$csvHeader.insert(1,'GUID')

$csv | select-object $csvHeader | export-csv new_attendees.csv -NoTypeInformation

相关问题