2010-01-15 71 views
38

我想在导入它们之前删除第一行约5000个文本文件。使用PowerShell删除顶部的文本文件

我对PowerShell仍然很陌生,所以不确定要搜索什么或如何处理这个问题。我目前的概念使用伪代码:

set-content file (get-content unless line contains amount) 

但是,我似乎无法弄清楚如何做一些像包含。

回答

30

它是不是最有效的世界,但这应该工作:

get-content $file | 
    select -Skip 1 | 
    set-content "$file-temp" 
move "$file-temp" $file -Force 
+0

当我尝试运行它时,似乎它在-skip上出错。这可能是来自不同的版本? – percent20 2010-01-15 20:41:39

+1

-Skip是PowerShell 2.0中的Select-Object的新增功能。另外,如果这些文件都是ascii,那么你可能想使用set-content -enc ascii。如果编码混合在一起,那么它会变得复杂,除非你不关心文件编码。 – 2010-01-15 20:51:57

+0

我安装了PowerShell 2.0,它现在正在工作。 – percent20 2010-01-15 21:06:14

10

使用变量符号,你可以不用临时文件:

${C:\file.txt} = ${C:\file.txt} | select -skip 1 

function Remove-Topline ([string[]]$path, [int]$skip=1) { 
    if (-not (Test-Path $path -PathType Leaf)) { 
    throw "invalid filename" 
    } 

    ls $path | 
    % { iex "`${$($_.fullname)} = `${$($_.fullname)} | select -skip $skip" } 
} 
1

skip`没”牛逼的工作,所以我的解决办法是

$LinesCount = $(get-content $file).Count 
get-content $file | 
    select -Last $($LinesCount-1) | 
    set-content "$file-temp" 
move "$file-temp" $file -Force 
29

虽然我真的很佩服从@hoge两个答案非常简洁的技术和一个包装函数来推广它,我鼓励upvotes它,我不得不评论其他两个使用临时文件的答案(它像黑板上的指甲一样啃着我!)。

假设该文件不是很大,你可以强制管道中离散的部分操作 - 从而避免了临时文件的必要性 - 与明智地使用括号:

(Get-Content $file | Select-Object -Skip 1) | Set-Content $file 

...或以简短的形式:

(gc $file | select -Skip 1) | sc $file 
7

我必须做同样的任务,gc | select ... | sc接手4   GB的RAM我的机器上,而读一1.6   GB的文件。在阅读整个文件后(至少读取字节数为Process Explorer),至少20分钟才完成,此时我必须杀死它。

我的解决方案是使用更多的.NET方法:StreamReader + StreamWriter。 一个伟大的答案讨论PERF看到这个答案:In Powershell, what's the most efficient way to split a large text file by record type?

下面是我的解决办法。是的,它使用的是临时文件,但对我来说,这并不重要(这是一个巨大再用SQL表的创建和插入语句文件):

PS> (measure-command{ 
    $i = 0 
    $ins = New-Object System.IO.StreamReader "in/file/pa.th" 
    $outs = New-Object System.IO.StreamWriter "out/file/pa.th" 
    while(!$ins.EndOfStream) { 
     $line = $ins.ReadLine(); 
     if($i -ne 0) { 
      $outs.WriteLine($line); 
     } 
     $i = $i+1; 
    } 
    $outs.Close(); 
    $ins.Close(); 
}).TotalSeconds 

,它返回:

188.1224443 
+0

IIRC这是因为围绕gc | select的括号意味着它在将管道穿过之前将整个文件读入内存。否则,打开的流会导致设置内容失败。对于大文件,我认为你的方法可能是最好的 – Alex 2013-03-15 15:58:16

+0

谢谢@AASoft,为您解决问题!我已经允许自己通过在每个循环中放弃比较操作来稍微改善它,例如25%的速度 - 请参阅[我的答案](http://stackoverflow.com/a/24746158/177710)了解详细信息。 – Oliver 2014-07-14 21:20:38

1
$x = get-content $file 
$x[1..$x.count] | set-content $file 

就是这么多。冗长的解释如下。 Get-content返回一个数组。我们可以“索引”数组变量,如thisother脚本专家帖子所示。

例如,如果我们定义一个这样的数组变量,

$array = @("first item","second item","third item") 

所以$阵列返回

first item 
second item 
third item 

那么我们就可以“索引”该阵列只提取其第一元素

$array[0] 

或仅其第二个

$array[1] 

range指数值从第2个到最后一个。

$array[1..$array.count] 
3

我刚刚从网站上了解到:

Get-ChildItem *.txt | ForEach-Object { (get-Content $_) | Where-Object {(1) -notcontains $_.ReadCount } | Set-Content -path $_ } 

或者您可以使用别名,使之短,像:

gci *.txt | % { (gc $_) | ? { (1) -notcontains $_.ReadCount } | sc -path $_ } 
+0

非常感谢这个解决方案。你能指出你提到的网站吗? – giordano 2016-08-11 15:31:08

-1

对于您可以使用此较小的文件:

& C:\ windows \ system32 \ more +1 oldfile.csv> newfile.csv | out-null

...但它不是非常有效的处理我的示例文件的16MB。它似乎没有终止并释放newfile.csv上的锁定。

4

通过AASoft's answer启发,我出去改善多一点:

  1. 避免循环变量$i比较0在每个循环
  2. 裹执行到try..finally阻止总是关闭正在使用的文件
  3. 使解决方案适用于任意数量的行以删除从文件
  4. 使用一个变量$p的开头引用当前目录

这些变化导致了下面的代码:

$p = (Get-Location).Path 

(Measure-Command { 
    # Number of lines to skip 
    $skip = 1 
    $ins = New-Object System.IO.StreamReader ($p + "\test.log") 
    $outs = New-Object System.IO.StreamWriter ($p + "\test-1.log") 
    try { 
     # Skip the first N lines, but allow for fewer than N, as well 
     for($s = 1; $s -le $skip -and !$ins.EndOfStream; $s++) { 
      $ins.ReadLine() 
     } 
     while(!$ins.EndOfStream) { 
      $outs.WriteLine($ins.ReadLine()) 
     } 
    } 
    finally { 
     $outs.Close() 
     $ins.Close() 
    } 
}).TotalSeconds 

第一个变化带来的处理时间我60 MB文件从5.3s降至4s。其余的变化更美观。

+0

您可能希望将'-and!$ ins.EndOfStream'添加到'for'循环的条件中,以涵盖文件的行少于'$ skip'的情况。 – AASoft 2017-11-10 07:11:36

+0

感谢您的领导!这就说得通了 :-) – Oliver 2017-11-10 11:32:21