从Powershell中的CSV中删除标题

从Powershell中的CSV中删除标题,powershell,csv,header,export-csv,Powershell,Csv,Header,Export Csv,需要从CSV文件中删除标题的帮助。文件导入到的工具有非常严格的要求。最上面一行必须是标题,然后是第2行日期:2019年8月19日。第三行应该包含没有标题的数据 尝试将其导入回并使用[1..-1]表示法删除顶行,以及尝试使用选择对象-skip 1将数据导入。还是不能让它工作 还尝试将对象数组写入TXT,但它只作为字段显示,而不是像CSV中那样基于选项卡。例如: 日期: 信息: 字段1: get-content "c:\users\user123\documents\adh\_$(get-date

需要从CSV文件中删除标题的帮助。文件导入到的工具有非常严格的要求。最上面一行必须是标题,然后是第2行日期:2019年8月19日。第三行应该包含没有标题的数据

尝试将其导入回并使用[1..-1]表示法删除顶行,以及尝试使用
选择对象-skip 1
将数据导入。还是不能让它工作

还尝试将对象数组写入TXT,但它只作为字段显示,而不是像CSV中那样基于选项卡。例如:

日期: 信息: 字段1:

get-content "c:\users\user123\documents\adh\_$(get-date (get-date).addDays($i) -f yyyy-MM-dd).csv" | Select-Object -Skip 1 | Set-Content "c:\users\user123\documents\adh\_$(get-date (get-date).addDays($i) -f yyyy-MM-dd).txt" 

即使在我尝试删除标题后,该文件仍然包含标题。

在测试环境中复制该文件,尝试添加-NoTypeInformation这可能会解决您的问题


-NoTypeInformation将删除元数据,因此在测试时要小心。

我可以通过生成测试CSV重现您的问题,如下所示:

Get Process |选择ProcessName、ID、SI |导出CSV C:\temp\test.CSV-NoTypeInformation

您偶然发现的是管道的一个有趣方面。我不知道它为什么这么做的具体原因,但有两种方法可以解决这个问题,即自动将标题放回CSV:

  • 将-NoClobber添加到输出文件:
    获取内容C:\temp\test.csv |选择-跳过1 |输出文件-文件路径“C:\temp\new.csv”-NoClobber
    这里需要注意的是,它不允许您覆盖使用Get Content打开的文件,因此您必须将其发送到单独的文件
  • 或者,您可以绕过管道,将
    Get Content C:\temp\test.csv | Select-Skip 1
    的结果存储到变量中,然后将该变量发送到常规的Out File调用。这将使您覆盖该文件

  • 获取包含字段头记录的.csv文件后,可以构建该文件。已生成
    csmem.csv
    文件,但有一个头记录。这将在前两(2)条记录上写入标题和日期,然后附加不带标题记录的.csv文件

    "The Title" | Out-File -FilePath "C:\src\t\sf.csv" -Encoding ascii
    (Get-Date).ToString('yyyy-MM-dd') | Out-File -FilePath "C:\src\t\sf.csv" -Encoding ascii -Append
    Get-Content -Path 'C:\src\t\csmem.csv' |
        Select-Object -Skip 1 |
        Out-File -FilePath "C:\src\t\sf.csv" -Encoding ascii -Append
    

    给定生成的示例文件:

    > Get-Content .\_2019-08-19.csv
    "COLA","ColB"
    "Test1","Foo"
    "Test2","Baz"
    "Test3","Bar"
    "Test4","Baz"
    "Test5","Baz"
    
    此脚本:

    ## Q:\Test\2019\08\20\SO_SO_57581085.ps1
    ## 
    $i = 1
    $BaseDir = 'C:\Users\user123\Documents\adh'
    # $BaseDir = (gi .).FullName
    $BaseName= '_{0:yyyy-MM-dd}' -f (Get-Date).AddDays(-$i)
    
    "Your Title`ndate: {0:M\/d\/yyyy}" -f (Get-Date).AddDays(-$i) | 
      Set-Content (Join-Path $BaseDir ($BaseName+'.txt')) # -Encoding if req.
    
    Get-Content (Join-Path $BaseDir ($BaseName+'.csv')) | 
      Select-Object -Skip 1 | 
        Add-Content (Join-Path $BaseDir ($BaseName+'.txt')) # -Encoding if req.
    
    生成此结果文件:

    > Get-Content .\_2019-08-19.txt
    Your Title
    date: 8/19/2019
    "Test1","Foo"
    "Test2","Baz"
    "Test3","Bar"
    "Test4","Baz"
    "Test5","Baz"
    

    听起来您的起点是一个内存中的对象数组,要转换为CSV而不带标题

    要获得没有标题的CSV表示,您无需使用
    导出CSV
    -只需通过管道传输到
    转换到CSV
    ,即可生成字符串数组,其第一个元素-标题行-您可以使用
    选择对象-跳过1
    跳过

    因此,您的整个文件可以通过单个可扩展字符串写入:

    # Format the date string.
    $i = 2 # sample value
    $dateString = '{0:yyyy-MM-dd}' -f (Get-Date).AddDays($i)
    
    # The input object array
    # $objArray = ...
    
    # Use an expandable here-string to write the output file.
    @"
    Title
    $dateString
    $($objArray | ConvertTo-Csv | Select-Object -Skip 1 | Out-String)
    "@ | Set-Content -NoNewline "c:\users\user123\documents\adh\_$dateString.txt" 
    

    至于你所尝试的:

    尝试将其导入回并使用[1..-1]表示法删除顶行

    [1..-1]
    不会跳过PowerShell中数组的第一个元素,因为
    1..-1
    是一个范围表达式,可扩展到以下索引列表:
    1,0,-1
    ;也就是说,您正提取3个元素:第二个(
    1
    ),第一个(
    0
    ),最后一个(
    -1

    还尝试将对象数组写入TXT,但它只作为字段显示,而不是像CSV中那样基于选项卡。例如:

    这听起来像是您使用了非导出Csv的东西将内存中的对象数组发送到了
    *.txt
    文件,而这不会给您Csv输出;听起来像是您使用了
    输出文件
    ,其中对象的格式与它们打印到控制台的方式相同,这是一种显示格式,不适合编程处理

    获取内容….csv |选择对象-跳过1 |设置内容….txt

    假设输入
    *.csv
    文件是用
    导出Csv-notype信息

    如果未使用
    -NoTypeInformation
    ,请使用
    -Skip 2
    ,即跳过另一行,以便跳过默认情况下作为第一行输出的
    导出Csv的类型注释行


    注意:Windows PowerShell中导出Csv的这一违反直觉的默认行为已在PowerShell Core中修复。

    我认为导出Csv时,
    -NoTypeInformation
    只是删除了该类型标题。我认为它对实际的CSV头没有任何影响。我可能是错的,虽然听起来您认为OP的问题是试图回写正在读取的同一个文件,但事实并非如此,因为问题中的命令会写入另一个文件(
    *.txt
    )。至于原因:管道流(逐个对象处理输入对象),因此write命令尝试将行写入仍然打开的文件,因为read命令(
    Get Content
    )尚未完成读取。一个简单的解决方法是将
    获取内容
    调用包含在
    (…)
    中,这将强制提前阅读:
    (获取内容…)…|设置内容…
    。不过,数据丢失的风险很小。您是否可以选择一个答案?