如何使用PowerShell打印文件的某一行?

nor*_*ben 24 powershell

我在这台服务器上没有一个像样的文本编辑器,但是我需要看看是什么导致某个文件的第10行出错.我确实有PowerShell ......

Fro*_* F. 23

它就像使用select一样简单:

Get-Content file.txt | Select -Index (line - 1)
Run Code Online (Sandbox Code Playgroud)

例如,获得第5行

Get-Content file.txt | Select -Index 4
Run Code Online (Sandbox Code Playgroud)

或者您可以使用:

(Get-Content file.txt)[4]
Run Code Online (Sandbox Code Playgroud)

  • 这不会首先将整个内容检索到内存中,这很糟糕吗? (2认同)

nor*_*ben 16

这将显示myfile.txt的第10行:

get-content myfile.txt | select -first 1 -skip 9

两个-first-skip是可选参数,并且-context,或者-last可以是在类似情况下是有用的.

  • 这适用于小文件.除非有什么变化,否则`Get-Content`会将整个文件读入内存.这并不总是适用于大文件. (2认同)

BAC*_*CON 6

您可以使用cmdlet-TotalCount参数来读取第一行,然后使用仅返回第n行:Get-ContentnSelect-Objectn

Get-Content file.txt -TotalCount 9 | Select-Object -Last 1;
Run Code Online (Sandbox Code Playgroud)

根据@CB的评论,这应该通过只读取包括第一n行而不是整个文件来提高性能.请注意,您可以使用别名-First-Head代替-TotalCount.


CB.*_*CB. 6

只是为了好玩,这里有一些测试:

# Added this for @Graimer's request ;) (not same computer, but one with HD little more
# performant...)
> measure-command { Get-Content ita\ita.txt -TotalCount 260000 | Select-Object -Last 1 }


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 28
Milliseconds      : 893
Ticks             : 288932649
TotalDays         : 0,000334412788194444
TotalHours        : 0,00802590691666667
TotalMinutes      : 0,481554415
TotalSeconds      : 28,8932649
TotalMilliseconds : 28893,2649


> measure-command { (gc "c:\ps\ita\ita.txt")[260000] }


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 9
Milliseconds      : 257
Ticks             : 92572893
TotalDays         : 0,000107144552083333
TotalHours        : 0,00257146925
TotalMinutes      : 0,154288155
TotalSeconds      : 9,2572893
TotalMilliseconds : 9257,2893


> measure-command { ([System.IO.File]::ReadAllLines("c:\ps\ita\ita.txt"))[260000] }


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 234
Ticks             : 2348059
TotalDays         : 2,71766087962963E-06
TotalHours        : 6,52238611111111E-05
TotalMinutes      : 0,00391343166666667
TotalSeconds      : 0,2348059
TotalMilliseconds : 234,8059



> measure-command {get-content .\ita\ita.txt | select -index 260000}


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 36
Milliseconds      : 591
Ticks             : 365912596
TotalDays         : 0,000423509949074074
TotalHours        : 0,0101642387777778
TotalMinutes      : 0,609854326666667
TotalSeconds      : 36,5912596
TotalMilliseconds : 36591,2596
Run Code Online (Sandbox Code Playgroud)

获胜者是: ([System.IO.File]::ReadAllLines( path ))[index]

  • 我真的很惊讶 `ReadAllLines()` 不仅更快,而且比 `Get-Content` 的两种用法快得多。顾名思义,它也在读取整个文件。无论如何,如果您也想尝试这种方法,我发布了另一种方法。此外,每当我使用 `Measure-Command` 对代码进行基准测试时,我通常会像这样运行它`1..10 | % { 测量命令 { ... } } | Measure-Object TotalMilliseconds -Average -Min -Max -Sum;` 这样我就可以从多次测试中获得更准确的数字。 (2认同)

BAC*_*CON 5

这是一个System.IO直接使用.NET 类的函数:

function GetLineAt([String] $path, [Int32] $index)
{
    [System.IO.FileMode] $mode = [System.IO.FileMode]::Open;
    [System.IO.FileAccess] $access = [System.IO.FileAccess]::Read;
    [System.IO.FileShare] $share = [System.IO.FileShare]::Read;
    [Int32] $bufferSize = 16 * 1024;
    [System.IO.FileOptions] $options = [System.IO.FileOptions]::SequentialScan;
    [System.Text.Encoding] $defaultEncoding = [System.Text.Encoding]::UTF8;
    # FileStream(String, FileMode, FileAccess, FileShare, Int32, FileOptions) constructor
    # http://msdn.microsoft.com/library/d0y914c5.aspx
    [System.IO.FileStream] $input = New-Object `
        -TypeName 'System.IO.FileStream' `
        -ArgumentList ($path, $mode, $access, $share, $bufferSize, $options);
    # StreamReader(Stream, Encoding, Boolean, Int32) constructor
    # http://msdn.microsoft.com/library/ms143458.aspx
    [System.IO.StreamReader] $reader = New-Object `
        -TypeName 'System.IO.StreamReader' `
        -ArgumentList ($input, $defaultEncoding, $true, $bufferSize);
    [String] $line = $null;
    [Int32] $currentIndex = 0;

    try
    {
        while (($line = $reader.ReadLine()) -ne $null)
        {
            if ($currentIndex++ -eq $index)
            {
                return $line;
            }
        }
    }
    finally
    {
        # Close $reader and $input
        $reader.Close();
    }

    # There are less than ($index + 1) lines in the file
    return $null;
}

GetLineAt 'file.txt' 9;
Run Code Online (Sandbox Code Playgroud)

调整$bufferSize变量可能会影响性能。使用默认缓冲区大小并且不提供优化提示的更简洁的版本可能如下所示:

function GetLineAt([String] $path, [Int32] $index)
{
    # StreamReader(String, Boolean) constructor
    # http://msdn.microsoft.com/library/9y86s1a9.aspx
    [System.IO.StreamReader] $reader = New-Object `
        -TypeName 'System.IO.StreamReader' `
        -ArgumentList ($path, $true);
    [String] $line = $null;
    [Int32] $currentIndex = 0;

    try
    {
        while (($line = $reader.ReadLine()) -ne $null)
        {
            if ($currentIndex++ -eq $index)
            {
                return $line;
            }
        }
    }
    finally
    {
        $reader.Close();
    }

    # There are less than ($index + 1) lines in the file
    return $null;
}

GetLineAt 'file.txt' 9;
Run Code Online (Sandbox Code Playgroud)

  • 我在寻找如何对**大**文件进行操作时偶然发现了这个问题-正是我所需要的。 (4认同)