在 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
我是 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