在 Powershell Import a CSV 中,每 10 行分成多个文件

In Powershell Import a CSV , split into multiple files every 10 lines

我是 powershell 编码的新手,我想做的是导入行数未知的 CSV 文件,然后每 10 行将其拆分为一个新的 CSV 文件。

例如,如果我输入一个 97 行的 CSV 文件,我希望有 9 个 10 行的文件和 1 个 7 行的文件。

我尝试了以下操作,Hostlist.csv 包含 35 个主机名,我得到 3 个文件,第一个文件缺少列表中的第一个主机,并且没有包含剩余主机的第 4 个文件。

$Hostlist = Get-Content '.\Hostlist.csv'
$BatchID = Get-Random
New-Item -ItemType Directory -Force -Path .$BatchID
$MaxBatch = 10
$line = 0
$i = 0
$File = 0

While ($line -lt $Hostlist.Length) {

    if ($i -gt $MaxBatch) {
        $Start = $line - $MaxBatch
        $File++
        $Hostlist[$Start..($line-1)] | Out-File ".$BatchID\Batch$File.csv" -Append -force
        $i = 0
    }
    $i++;
    $line++
}

您的代码不会生成正确的 CSV 文件,因为您没有处理 header 信息,也没有使用 Import-CSV 让您处理自然导出为CSV。所以我使用了一些为另一个人编写的代码。

$SourceDir = $env:TEMP
$SourceFile = 'Source.csv'
$FullSourceFile = Join-Path -Path $SourceDir -ChildPath $SourceFile

$BatchSize = 4

$OutputDir = $env:TEMP
$OutputFile = 'Output.csv'
$FullOutputFile = Join-Path -Path $OutputDir -ChildPath $OutputFile

#$InCSV = Import-Csv -Path $FullSourceFile

#region - fake reading in CSV
# fake reading in a CSV file
#    in real life, use Import-CSV above
$InCSV = @'
Col_1,Col_2,Col_3,Col_4
row-1-1, row-1-2, row-1-3, row-1-4
row-2-1, row-2-2, row-2-3, row-2-4
row-3-1, row-3-2, row-3-3, row-3-4
row-4-1, row-4-2, row-4-3, row-4-4
row-5-1, row-5-2, row-5-3, row-5-4
row-6-1, row-6-2, row-6-3, row-6-4
row-7-1, row-7-2, row-7-3, row-7-4
row-8-1, row-8-2, row-8-3, row-8-4
row-9-1, row-9-2, row-9-3, row-9-4
row-10-1, row-10-2, row-10-3, row-10-4
'@ | ConvertFrom-Csv
#endregion - fake reading in CSV

$Count = 0
$Remaining = $InCSV.Count
$Batch = [System.Collections.Generic.List[PSObject]]::new()
foreach ($IC_Item in $InCSV)
    {
    $Count ++
    $Ready = $False

    $Batch.Add($IC_Item)

    if ($Count -eq $BatchSize)
        {
        $Ready = $True
        $Count = 0
        }

    $Remaining --
    if ($Remaining -eq 0)
        {
        $Ready = $True
        }

    if ($Ready)
        {
        $TimeStamp = Get-Date -Format 'yyyy-MM-dd__HH-mm-ss__fff'
        $NewFullOutputFile = $FullOutputFile.Replace('.csv', "$TimeStamp.csv")

        $Batch | 
            Export-Csv -LiteralPath $NewFullOutputFile -NoTypeInformation

        $Batch.Clear()
        }
    }

没有屏幕输出。这是第一个 CSV 的内容...

"Col_1","Col_2","Col_3","Col_4"
"row-1-1","row-1-2","row-1-3","row-1-4"
"row-2-1","row-2-2","row-2-3","row-2-4"
"row-3-1","row-3-2","row-3-3","row-3-4"
"row-4-1","row-4-2","row-4-3","row-4-4"

最后一个 CSV 的内容...

"Col_1","Col_2","Col_3","Col_4"
"row-9-1","row-9-2","row-9-3","row-9-4"
"row-10-1","row-10-2","row-10-3","row-10-4"

顺便说一句:

  • 如果您的输入文件是 CSV 文件并且您希望输出文件也是 CSV 文件,则必须为每个文件写一个 header 行。

  • 你的代码没有尝试这样做,所以我假设你只是在处理 line-oriented plain-text 文件,尽管 .csv 文件名扩展。

the first file missing the first host

由于你处理一个批次的条件是$i -gt $MaxBatch,当你先进入if块时,$i$line都是11,并且$Start = $line - $MaxBatch 因此是 1,即 second 行,因为 $Start 被用作基于 0 的数组索引。

there is no 4th file with remaining host.

由于您只处理 $i -gt $MaxBatch 的批次,因此行数不能被 $MaxBatch 整除的输入文件将始终缺少最后一批,因为最后一个,不完整的批次永远不会满足 if 条件。


我建议通过计算批次的数量并逐批循环来简化您的代码,如以下简化示例所示,它将 10 行输入分成 3 个批次:

# Simulate the list of hosts
$HostList = 1..10 -replace '^', 'host$&' # 'host1', 'host2', ...

# Batch size
$MaxBatch = 3

foreach ($batch in 1..[math]::Ceiling($Hostlist.Count / $MaxBatch)) {
  write-verbose -Verbose "File index (batch number): $batch"
  $startNdx = ($batch-1) * $MaxBatch
  $Hostlist[$startNdx..($startNdx + $MaxBatch - 1)]
}

请注意如何在 batch-count 计算 $Hostlist.Count / $MaxBatch 中使用 [math]::Ceiling() 确保最后的不完整批次也得到处理。

除非您有 Set-StrictMode -Version 3 或更高的效果,否则在用于在最终的、不完整的批处理中对数组进行切片的 .. 范围表达式中超出数组上限是可以的 - PowerShell 将简单地忽略超出上限的索引。

以上结果:

VERBOSE: File index (batch number): 1
host1
host2
host3
VERBOSE: File index (batch number): 2
host4
host5
host6
VERBOSE: File index (batch number): 3
host7
host8
host9
VERBOSE: File index (batch number): 4
host10