使用PowerShell删除顶行文本文件

Bud*_*sey 47 powershell

我想在导入之前删除大约5000个文本文件的第一行.

我仍然是PowerShell的新手,所以不确定要搜索什么或如何处理它.我目前使用伪代码的概念:

set-content file (get-content unless line contains amount)
Run Code Online (Sandbox Code Playgroud)

但是,我似乎无法弄清楚如何做像contains这样的事情.

Ric*_*erg 36

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

get-content $file |
    select -Skip 1 |
    set-content "$file-temp"
move "$file-temp" $file -Force
Run Code Online (Sandbox Code Playgroud)

  • -Skip 是 PowerShell 2.0 中 Select-Object 的新增功能。此外,如果文件都是 ascii,那么您可能需要使用 set-content -enc ascii。如果编码混合,那么除非您不关心文件编码,否则它会变得更加棘手。 (2认同)

Mic*_*ens 35

虽然我真的很钦佩@hoge的答案,一个非常简洁的技术和一个包装函数来概括它,我鼓励它的赞成,我不得不评论使用临时文件的其他两个答案(它像指甲一样啃我在黑板上!).

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

(Get-Content $file | Select-Object -Skip 1) | Set-Content $file
Run Code Online (Sandbox Code Playgroud)

......或简短形式:

(gc $file | select -Skip 1) | sc $file
Run Code Online (Sandbox Code Playgroud)


小智 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" }
}
Run Code Online (Sandbox Code Playgroud)


AAS*_*oft 8

我只需要执行相同的任务,并gc | select ... | sc在读取1.6 GB文件时在我的机器上占用4 GB的RAM.在读完整个文件后(至于Process Explorer中的Read Bytes报告),它至少没有完成至少20分钟,此时我不得不将其杀死.

我的解决方案是使用更多的.NET方法:StreamReader+ StreamWriter.请参阅这个答案以获得一个讨论perf的好答案:在Powershell中,按记录类型拆分大型文本文件的最有效方法是什么?

以下是我的解决方案.是的,它使用一个临时文件,但在我的情况下,它没关系(这是一个巨大的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
Run Code Online (Sandbox Code Playgroud)

它返回:

188.1224443
Run Code Online (Sandbox Code Playgroud)


noa*_*oam 5

$x = get-content $file
$x[1..$x.count] | set-content $file
Run Code Online (Sandbox Code Playgroud)

就这么多。接下来是冗长无聊的解释。获取内容返回一个数组。我们可以“索引”数组变量,如本文其他脚本专家帖子中所示。

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

$array = @("first item","second item","third item")
Run Code Online (Sandbox Code Playgroud)

所以 $array 返回

first item
second item
third item
Run Code Online (Sandbox Code Playgroud)

然后我们可以“索引”该数组以仅检索其第一个元素

$array[0]
Run Code Online (Sandbox Code Playgroud)

或者只是第二个

$array[1]
Run Code Online (Sandbox Code Playgroud)

或从第二个到最后一个的索引值范围。

$array[1..$array.count]
Run Code Online (Sandbox Code Playgroud)


Oli*_*ver 5

受到AASoft答案的启发,我出去改进了一点:

  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
Run Code Online (Sandbox Code Playgroud)

第一个更改使我的60 MB文件的处理时间从下降5.3s4s.其余的变化更具美感.