2013-02-07 87 views
14

我在這臺服務器上沒有像樣的文本編輯器,但我需要查看是什麼導致某個文件的第10行有錯誤。我有PowerShell的,但...如何使用PowerShell打印文件的某一行?

+3

'(get-content myfile.txt)[9]'? –

+0

絕佳的選擇! – northben

+0

是的,問題是,與大文件可以真的很慢,因爲所有的文件被讀取之前返回[索引] –

回答

11

這將顯示myfile.txt的10號線:

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

兩個-first-skip是可選的參數,和-context,或-last可能是有用的相似的情況。

+0

這將工作得很好爲小文件。除非有什麼改變,'Get-Content'會將整個文件讀入內存。這對大文件並不總是適用。 – lit

14

這是因爲使用select一樣簡單:

Get-Content file.txt | Select -Index (line - 1) 

例如獲得第5行

Get-Content file.txt | Select -Index 4 

或者你可以使用:

(Get-Content file.txt)[4] 
1

您可以使用Get-Content cmdlet-TotalCount參數讀取第一n線,然後用Select-Object只返回n日線:

Get-Content file.txt -TotalCount 9 | Select-Object -Last 1; 

根據來自@CB的評論這應該通過只讀取第012行而不是整個文件來提高性能。請注意,您可以使用別名-First-Head代替-TotalCount

0

只是爲了好玩,在這裏一些測試:

#Added this for @Graimer's request ;) (not same computer, but one with HD little more #performant...) 

措施命令{獲取內容東郡\ ita.txt -totalcount 260000 |選擇-對象-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 

獲獎者是:([System.IO.File]::ReadAllLines(path))[index]

+0

@Bacon的答案呢?因爲你已經有一個示例文件:-) –

+0

@Graimer增加:)。所有這些測試都是爲了尋找大型指數的大文件,我認爲對於小指數的價值來說,結果可能會有所不同。每個測試都是在新的powershell會話中完成的,以避免高清預緩存功能。 –

+0

我真的很驚訝,'ReadAllLines()'不僅更快,而且比'Get-Content'的兩次使用快得多。顧名思義,它也讀取整個文件。無論如何,我發佈了另一種方法,如果你想嘗試一種方法。另外,無論何時我使用'Measure-Command'來測試代碼,我通常都會像這樣運行它'1..10 | %{Measure-Command {...}} | Measure-Object TotalMilliseconds -Average -Min -Max -Sum;'所以我可以從多個測試運行中獲得更準確的數字。 – BACON

2

這裏是直接使用.NET的System.IO類的函數:

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; 

扭捏$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; 
+1

過度工程:請參閱BACON的SO解決方案,以便快速閱讀文本文件。 :) – northben

+0

嗯,你沒有要求一個_quick_方式... – BACON

+2

我偶然發現這個問題,同時尋找如何爲一個** large **文件做到這一點 - 正是我所需要的。 – Tao

0

爲了減少內存消耗和加快搜索,你可以使用Get-Content命令的-ReadCount選項( https://technet.microsoft.com/ru-ru/library/hh849787.aspx)。

當您使用大型文件時,這可以節省數小時。

下面是一個例子:

$n = 60699010 
$src = 'hugefile.csv' 
$batch = 100 
$timer = [Diagnostics.Stopwatch]::StartNew() 

$count = 0 
Get-Content $src -ReadCount $batch -TotalCount $n | % { 
    $count += $_.Length 
    if ($count -ge $n) { 
     $_[($n - $count + $_.Length - 1)] 
    } 
} 

$timer.Stop() 
$timer.Elapsed 

這將打印$ N行和經過時間。

相關問題