Comando equivalente coda Unix in Windows Powershell


349

Devo guardare le ultime righe di un file di grandi dimensioni (la dimensione tipica è 500 MB-2 GB). Sto cercando un equivalente del comando Unix tailper Windows Powershell. Alcune alternative disponibili su sono,

http://tailforwin32.sourceforge.net/

e

Get-Content [nome file] | Select-Object -Last 10

Per me, non è consentito utilizzare la prima alternativa e la seconda alternativa è lenta. Qualcuno sa di un'implementazione efficiente di tail per PowerShell.


2
Come possiamo sapere se ti sarà permesso usare ciò che ti suggeriamo se non dici perché non ti è permesso usare la prima alternativa?
Gabe,

3
Qualche motivo per cui non puoi usare il tailcomando fornito in sourceforge.net/projects/unxutils/files/unxutils/current/… ?
Gabe,

1
questo è in una macchina di produzione in cui non mi è stato permesso di copiare alcun file eseguibile esterno. Alcune strane politiche. :) Non posso farci niente. Grazie per il link Unxutils.
Mutelogan,

https://devcentral.f5.com/blogs/us/unix-to-powershell-tail dimostra la pura implementazione PoSH di questo.
Yevgeniy,

Non è necessario utilizzare Select-Object: Get-Content [filename] -last 10e aggiungere -tailper -f
MortenB il

Risposte:


492

Utilizzare il -waitparametro con Get-Content, che visualizza le righe man mano che vengono aggiunte al file. Questa funzionalità era presente in PowerShell v1, ma per qualche motivo non è stata ben documentata in v2.

Ecco un esempio

Get-Content -Path "C:\scripts\test.txt" -Wait

Una volta eseguito questo, aggiorna e salva il file e vedrai le modifiche sulla console.


16
Interessante. Avrei pensato che anche tutti gli argomenti esistenti apparissero in aiuto, ma man gc -par waitmi dice che non esiste alcun parametro. Ma penso che questo non risolva il problema che l'OP ha, dal momento che lo hanno chiesto tail, tail -fe non anche un'implementazione efficiente. Dal momento che questo legge anche il file completo prima di restituire le ultime righe, questo è doloroso per le dimensioni del file che si aspettano.
Joey,

5
Cordiali saluti, questo è ciò che fa l'implementazione Get-FileTail (alias tail) in PSCX. Se sei curioso puoi guardare il codice sorgente: pscx.codeplex.com/SourceControl/changeset/view/78514#1358075
Keith Hill il

7
@Joey -Wait è un parametro dinamico che si applica solo al provider FileSystem. GC può essere utilizzato su qualsiasi provider che implementa tale API. L'unico modo, oltre alla documentazione che conosco per scoprirli, è usare (gcm Get-Content) .Parametri all'interno del percorso del provider appropriato. Non utilizzare l'alias "gc" perché i parametri dinamici non verranno visualizzati.
JasonMArcher,

11
So che è stato un po 'di tempo fa, ma questo richiede che il processo di scrittura sul file si apra, accoda, chiuda prima che Get-Content funzioni. Se il processo di scrittura non chiude mai il file, non funzionerà, il che non è il caso di tail -f.
David Newcomb,

15
Stranamente, -Wait mi mostra nuove righe solo quando accedo a un file di registro in qualche modo (come selezionarlo in Esplora risorse). Tail fornisce aggiornamenti man mano che nuove righe vengono scritte nel mio file. Con -Wait, posso lasciare una finestra di PowerShell aperta felicemente senza mostrare nuove righe durante la scrittura del file. Se poi pop-up e faccio clic sul file in Esplora risorse, improvvisamente PowerShell "si sveglia" e raggiunge le linee rimanenti. è un insetto?
JoshL

198

Per completezza, menzionerò che Powershell 3.0 ora ha un flag -Tail su Get-Content

Get-Content ./log.log -Tail 10

ottiene le ultime 10 righe del file

Get-Content ./log.log -Wait -Tail 10

ottiene le ultime 10 righe del file e ne attende altre

Inoltre, per quegli utenti * nix, tieni presente che la maggior parte dei sistemi alias si basa su Get-Content, quindi di solito funziona

cat ./log.log -Tail 10

@LauraLiparulo in che modo non funziona? L'ho usato prima sicuramente.
George Mauer,

4
L'ho appena usato e ha funzionato perfettamente in questo formatoGet-Content .\test.txt -Wait -Tail 1
Coops l'

@LauraLiparulo - Funziona anche per me:Get-Content -Path .\sync.log -Wait -Tail 10
elika kohen,

Su ISE, usavo while ($ true) / sleep e sono passato a questo, ma anche questo blocca l'intero ISE e non è possibile eseguire script su altre schede. Devo solo avviare una nuova istanza ISE?
Teoman Shipahi,

@Teomanshipahi In che modo il -Waitparametro non ha funzionato per te?
George Mauer,

116

A partire dalla versione 3.0 di PowerShell, il cmdlet Get-Content ha un parametro -Tail che dovrebbe aiutare. Consultare la guida in linea della libreria technet per Get-Content.



4
Nota per alcuni: PS 3.0 non è disponibile per Windows XP e Vista.
tjmoore,

1
Uso la tecnica menzionata da Dan ma la registro nel mio $ PROFILE. Aprilo con il blocco note $ PROFILE. Quindi, nel documento di testo, creare una nuova funzione: funzione Tail ($ percorso) {Get-content -tail 15 -path $ path -wait} In questo modo è possibile accedere alla funzione ogni volta che si avvia PowerShell.
Jake Nelson,

Questa dovrebbe essere la risposta accettata. -Il flag di attesa menzionato nella risposta attualmente accettata non funziona più.
Abdullah Leghari,

21

Ho usato alcune delle risposte fornite qui, ma solo un avvertimento

Get-Content -Path Yourfile.log -Tail 30 -Wait 

masticherò memoria dopo un po '. Un collega ha lasciato una tale "coda" in su nell'ultimo giorno ed è salito a 800 MB. Non so se la coda Unix si comporti allo stesso modo (ma ne dubito). Quindi va bene usare per applicazioni a breve termine, ma fai attenzione.


18

PowerShell Community Extensions (PSCX) fornisce il Get-FileTailcmdlet . Sembra una soluzione adatta per l'attività. Nota: non l'ho provato con file estremamente grandi, ma la descrizione dice che codifica in modo efficiente il contenuto ed è progettato per file di registro di grandi dimensioni.

NAME
    Get-FileTail

SYNOPSIS
    PSCX Cmdlet: Tails the contents of a file - optionally waiting on new content.

SYNTAX
    Get-FileTail [-Path] <String[]> [-Count <Int32>] [-Encoding <EncodingParameter>] [-LineTerminator <String>] [-Wait] [<CommonParameters>]

    Get-FileTail [-LiteralPath] <String[]> [-Count <Int32>] [-Encoding <EncodingParameter>] [-LineTerminator <String>] [-Wait] [<CommonParameters>]

DESCRIPTION
    This implentation efficiently tails the cotents of a file by reading lines from the end rather then processing the entire file. This behavior is crucial for ef
    ficiently tailing large log files and large log files over a network.  You can also specify the Wait parameter to have the cmdlet wait and display new content
    as it is written to the file.  Use Ctrl+C to break out of the wait loop.  Note that if an encoding is not specified, the cmdlet will attempt to auto-detect the
     encoding by reading the first character from the file. If no character haven't been written to the file yet, the cmdlet will default to using Unicode encoding
    . You can override this behavior by explicitly specifying the encoding via the Encoding parameter.

1
C'è un bug nella versione corrente che è stato corretto in bit giornalieri. Consiglierei di prendere gli ultimi bit e compilarli almeno fino a quando non avremo rilasciato una versione aggiornata.
Keith Hill,

7
La versione 2.0 richiede secoli per mostrare le ultime 10 righe di un file csv da 1 GB, e diversamente da Get-Content [filename] | Select-Object -Last 10esso non può essere interrotto
Jader Dias,

15

Solo alcune aggiunte alle risposte precedenti. Esistono alias definiti per Get-Content, ad esempio se sei abituato a UNIX ti potrebbe piacere cat, e ci sono anche typee gc. Quindi invece di

Get-Content -Path <Path> -Wait -Tail 10

tu puoi scrivere

# Print whole file and wait for appended lines and print them
cat <Path> -Wait
# Print last 10 lines and wait for appended lines and print them
cat <Path> -Tail 10 -Wait

3

Utilizzando Powershell V2 e versioni precedenti, get-content legge l'intero file, quindi non mi è stato utile. Il codice seguente funziona per quello che mi serviva, anche se probabilmente ci sono alcuni problemi con la codifica dei caratteri. Questo è effettivamente tail -f, ma potrebbe essere facilmente modificato per ottenere gli ultimi x byte o le ultime x linee se si desidera cercare le interruzioni di riga all'indietro.

$filename = "\wherever\your\file\is.txt"
$reader = new-object System.IO.StreamReader(New-Object IO.FileStream($filename, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [IO.FileShare]::ReadWrite))
#start at the end of the file
$lastMaxOffset = $reader.BaseStream.Length

while ($true)
{
    Start-Sleep -m 100

    #if the file size has not changed, idle
    if ($reader.BaseStream.Length -eq $lastMaxOffset) {
        continue;
    }

    #seek to the last max offset
    $reader.BaseStream.Seek($lastMaxOffset, [System.IO.SeekOrigin]::Begin) | out-null

    #read out of the file until the EOF
    $line = ""
    while (($line = $reader.ReadLine()) -ne $null) {
        write-output $line
    }

    #update the last max offset
    $lastMaxOffset = $reader.BaseStream.Position
}

Ho trovato la maggior parte del codice per farlo qui .


1
È vero che Get-Content con l'opzione -Tail legge l'intero file? Su file di grandi dimensioni mi sembra OK.
Govert,

Credo che dipenda dalla versione PS. Ho aggiornato la risposta. Ero bloccato su un server senza la possibilità di installare nulla al momento, quindi il codice sopra era utile.
hajamie,

3

Ho preso la soluzione di @ hajamie e l'ho racchiusa in un involucro di script leggermente più conveniente.

Ho aggiunto un'opzione per iniziare da un offset prima della fine del file, in modo da poter utilizzare la funzionalità di coda di leggere una certa quantità dalla fine del file. Si noti che l'offset è in byte, non in righe.

C'è anche un'opzione per continuare ad aspettare più contenuti.

Esempi (supponendo che lo salvi come TailFile.ps1):

.\TailFile.ps1 -File .\path\to\myfile.log -InitialOffset 1000000
.\TailFile.ps1 -File .\path\to\myfile.log -InitialOffset 1000000 -Follow:$true
.\TailFile.ps1 -File .\path\to\myfile.log -Follow:$true

Ed ecco la sceneggiatura stessa ...

param (
    [Parameter(Mandatory=$true,HelpMessage="Enter the path to a file to tail")][string]$File = "",
    [Parameter(Mandatory=$true,HelpMessage="Enter the number of bytes from the end of the file")][int]$InitialOffset = 10248,
    [Parameter(Mandatory=$false,HelpMessage="Continuing monitoring the file for new additions?")][boolean]$Follow = $false
)

$ci = get-childitem $File
$fullName = $ci.FullName

$reader = new-object System.IO.StreamReader(New-Object IO.FileStream($fullName, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [IO.FileShare]::ReadWrite))
#start at the end of the file
$lastMaxOffset = $reader.BaseStream.Length - $InitialOffset

while ($true)
{
    #if the file size has not changed, idle
    if ($reader.BaseStream.Length -ge $lastMaxOffset) {
        #seek to the last max offset
        $reader.BaseStream.Seek($lastMaxOffset, [System.IO.SeekOrigin]::Begin) | out-null

        #read out of the file until the EOF
        $line = ""
        while (($line = $reader.ReadLine()) -ne $null) {
            write-output $line
        }

        #update the last max offset
        $lastMaxOffset = $reader.BaseStream.Position
    }

    if($Follow){
        Start-Sleep -m 100
    } else {
        break;
    }
}


0

Molto semplice, ma fa quello che ti serve senza moduli aggiuntivi o requisiti di versione PS:

while ($true) {Clear-Host; gc E:\test.txt | select -last 3; sleep 2 }


4
È brutale su file di grandi dimensioni.
Pecos Bill,

La mia soluzione alternativa era: while($true) { Clear-Host; Get-Content <filename> -tail 40; sleep 1 }:)
NoLifeKing

0

Probabilmente è troppo tardi per rispondere, ma prova questo

Get-Content <filename> -tail <number of items wanted>

0

Ci sono state molte risposte valide, tuttavia, nessuna di esse ha la stessa sintassi di tail in linux . La seguente funzione può essere memorizzata nella $Home\Documents\PowerShell\Microsoft.PowerShell_profile.ps1persistenza (consultare la documentazione dei profili PowerShell per maggiori dettagli).

Questo ti permette di chiamare ...

tail server.log
tail -n 5 server.log
tail -f server.log
tail -Follow -Lines 5 -Path server.log

che si avvicina molto alla sintassi di Linux.

function tail {
<#
    .SYNOPSIS
        Get the last n lines of a text file.
    .PARAMETER Follow
        output appended data as the file grows
    .PARAMETER Lines
        output the last N lines (default: 10)
    .PARAMETER Path
        path to the text file
    .INPUTS
        System.Int
        IO.FileInfo
    .OUTPUTS
        System.String
    .EXAMPLE
        PS> tail c:\server.log
    .EXAMPLE
        PS> tail -f -n 20 c:\server.log
#>
    [CmdletBinding()]
    [OutputType('System.String')]
    Param(
        [Alias("f")]
        [parameter(Mandatory=$false)]
        [switch]$Follow,

        [Alias("n")]
        [parameter(Mandatory=$false)]
        [Int]$Lines = 10,

        [parameter(Mandatory=$true, Position=5)]
        [ValidateNotNullOrEmpty()]
        [IO.FileInfo]$Path
    )
    if ($Follow)
    {
        Get-Content -Path $Path -Tail $Lines -Wait
    }
    else
    {
        Get-Content -Path $Path -Tail $Lines
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.