【问题标题】:How to delete date-based lines from files using PowerShell如何使用 PowerShell 从文件中删除基于日期的行
【发布时间】:2012-03-06 06:14:42
【问题描述】:

我有一些 CSV 文件,我需要删除所有包含大于指定日期的日期的行。我将如何在 PowerShell 中执行此操作?

顺便说一句:这里是日期格式:09/29/2011

示例:我想删除所有包含大于 09/29/2011 的日期的行。

【问题讨论】:

  • 您有示例文件或摘录吗?日期是否始终在所有文件的同一列中,还是可以在行中的任何位置?
  • 日期似乎总是在第二列。以下是其中一行的摘录:000329|09/30/2011|BLNDCOM|Items||||||||||||||||||||||1||1||||||||3|1||2|||||||||||1||||1||2|1||2||1|1|2|3|1|1|1|4|1|1|1||1|3|||||2|||1||||||||2|||||||||||
  • 实际上,在仔细检查 CSV 文件后,看起来整个用竖线分隔的行都被塞进了第一列。
  • 请编辑您的问题。评论不支持多行,无论如何正确回答信息很重要。
  • 乔伊,你能详细说明一下吗?如何编辑我的问题?我还是个菜鸟,所以我边走边学…… ;-) 谢谢!

标签: powershell csv


【解决方案1】:
 foreach ($file in gci *.csv){
   (gc $file) |
     ? {[datetime]$_.split('|')[1] -lt '09/29/2011'
     } | set-content $file

 }

假设这是一个以竖线分隔的文件。

【讨论】:

  • 谢谢,mjolinor!我喜欢你漂亮整洁的代码。越少越好。 ;-) 顺便说一句:效果很好!
  • +1 用于使用 set-content 并提醒我它替换了文件的内容!
  • @mjolinor - 如何修改您的代码以根据大于或等于“指定日期”的日期拆分 CSV 文件并以 1 周为增量?您的代码帮助我创建一个 CSV 文件,其中包含 2011 年 9 月 29 日之前的所有日期的行,但现在我需要创建其他 CSV 文件,其中包含日期为 >= 指定日期的行,并且每个 CSV 文件都需要包含日期范围为 1 周。提前致谢!
  • 您希望这些 .csv 文件如何命名?
  • 类似这样的东西:originalfilename_startdate_enddate.csv
【解决方案2】:

比起简洁,我更喜欢清晰:

param (
    [parameter(Mandatory = $true)] [string] $csvFileName,
    [parameter(Mandatory = $true)] [datetime] $date
)

try
{
    $Error.Clear()

    if (!(Test-Path $csvFileName))
        { throw "Could not find file $csvFileName" }

    $newContent = Get-Content $csvFileName |    ?{
        ([regex]::matches($_, "[0-9]{2}/[0-9]{2}/[0-9]{4}") | %{[DateTime] $_.value -lt $date})
    } 

    $newContent | Set-Content $csvFileName
}

catch
{
    Write-Host "$($MyInvocation.InvocationName): $_"
}

【讨论】:

  • 小心那把斧头,尤金。这将匹配 ALL 一行中的日期,在您的 Excel 文件中的任何位置。如果您只想过滤出 one 列,则必须调整正则表达式。
【解决方案3】:

好的,无论如何,似乎该行中只有一个看起来像日期的东西,所以我们可以过滤它:

Get-ChildItem *.csv | # adapt if necessary
  ForEach-Object {
    (Get-Content $_) | # the parentheses are important so the entire file is read at once
      Where-Object { # now we process the file line by line
        # find the date                       ↓ suppress the boolean output
        $_ -match '\|(\d{2}/\d{2}/\d{4})\|' | Out-Null

        # this only works if every line contains a date. Hopefully it does.
        $date = [DateTime]($Matches[1])

        # Finally the comparison we wanted in the first place
        # This is the condition for all lines that are *retained* (hence less than)
        $date -lt '09/29/2011'
      } | Out-File $_ # use -Encoding ASCII/UTF8/Unicode depending on your needs.
                      # Maybe ASCII is enough
  }

或更短:

gci *.csv | % {
  (gc $_) |
    ? {
      $null = $_ -match '\|(\d{2}/\d{2}/\d{4})\|'
      [DateTime]$Matches[1] -lt '09/29/2011'
    } |
    Out-File $_
}

【讨论】:

  • 谢谢,乔伊。我尝试使用上面的代码,但它给了我这些错误:Bad argument to operator '-match': parsing "\|(\d{2}/\d{2}/\d{4}\)|" - Not enough )'s.. + $null = $_ -match <<<< '\|(\d{2}/\d{2}/\d{4}\)|' + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : BadOperatorArgument Cannot convert null to type "System.DateTime". + [DateTime]$Matches[ <<<< 1] -lt '09/29/2011' + CategoryInfo : NotSpecified: (:) [], RuntimeException + FullyQualifiedErrorId : RuntimeException
  • 谢谢乔伊!您修改后的代码似乎有效。当我在我的 2 MB CSV 文件上运行它时,它按预期删除了 2749 行。然而,奇怪的是 CSV 文件现在变大了(3.17MB)。不知道为什么会这样。注意:我还运行了 mjolinor 的代码并得到了相同的结果(删除了 2749 行),但 CSV 文件为 1.85 MB,这是我所期望的(比以前小)。我比较了您的代码和 mjolinor 代码的 CSV 输出,文件是相同的(大小除外)。奇怪的。 :-)
  • UTF-16 每个字符占用两个字节。这就是为什么我包含有关编码的评论。也许Set-Content 会保留文件的编码。
  • Set-content 和 add-content 不做任何格式化。它们没有 -Encoding 参数,也无法更改原始编码。
  • mjolinor:-Encoding 参数是动态的,并且肯定存在于文件系统提供程序中。它甚至可以正常工作。但是Out-File 默认为 UTF-16,Set-Content 实际上会保留原始文件的编码(虽然没有记录)。
【解决方案4】:

您需要创建一个新的清理后的 csv 文件:

假设这是你的 csv:

col1,date,col3
aaaaa,05/05/2010,rwer
bdfdfg,06/29/2011,reewr
dsfsdf,08/05/2012,dsfsd

这样做:

import-csv .\myoriginal.csv -delimiter '|' | ? { [datetime]$_.date -ge [datetime]"09/29/2011"} | Export-Csv -NoTypeInformation -Path .\mycleaned.csv -delimiter '|'

然后你可以删除原始的csv

remove-item .\myoriginal.csv

【讨论】:

  • 这将删除所有类型的行,但可能不仅仅是他们想要的行。请记住,如果 CSV 没有类型信息,那么您得到的只是字符串。你在那里比较字符串。如果他们使用理智的日期格式,那没问题,但是这样......只需在其中加上10/02/2009 并观看;-)
  • 嗯..运行上述脚本会从我的 CSV 文件中删除所有内容,或者至少 Export-Csv 文件不包含任何数据。这是 CSV 文件中的示例字符串(行):000329|10/01/2011|BLNDCOM|Items
  • @乔伊。谢谢你。我修复了将管道值和“日期”转换为 [日期时间]。
  • 感谢更新代码,但我收到以下错误:Import-Csv : Cannot process argument because the value of argument "name" is invalid. Change the value of the "name" argument and run the operation again.
  • 由于 PowerShell 的类型强制规则,只需转换左值即可;)
【解决方案5】:

我早上为你写了一个脚本,删除每一行都有你指定的模式。 您应该运行以下脚本:

myscruipt.sh YOURDATYE YOURCSVFILE

myscript.sh:

#!/bin/bash
    declare -a  num
    num=`egrep -n "$1" yahoo_ab.csv |awk 'BEGIN{FS=":";}{for (i=0 ; i<NF ; i++) print $1; } '`
    while true; do 
        for i in $num ; do 
            sed -i "$i d" $2 ;
        done;
        egrep $1 $2;
        if [ $? = 1 ]; then break; fi;
    done;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-30
    • 2021-06-20
    • 2015-04-05
    • 2012-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多