2010-01-15 68 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