Komenda odpowiednika ogona uniksowego w Windows Powershell


349

Muszę spojrzeć na kilka ostatnich wierszy dużego pliku (typowy rozmiar to 500 MB-2 GB). Szukam odpowiednika polecenia Unix taildla Windows Powershell. Kilka dostępnych alternatyw to:

http://tailforwin32.sourceforge.net/

i

Get-Content [nazwa pliku] | Wybierz obiekt - ostatni 10

Dla mnie nie wolno używać pierwszej alternatywy, a druga alternatywa jest powolna. Czy ktoś wie o skutecznej implementacji taila dla PowerShell.


2
Skąd możemy wiedzieć, czy będziesz mógł korzystać z tego, co sugerujemy, jeśli nie powiesz, dlaczego nie możesz użyć pierwszej alternatywy?
— Gabe,

3
Z jakiegokolwiek powodu nie możesz użyć tailpolecenia podanego w sourceforge.net/projects/unxutils/files/unxutils/current/… ?
— Gabe,

1
to jest na maszynie produkcyjnej, gdzie nie wolno mi było kopiować żadnych zewnętrznych plików wykonywalnych. Niektóre dziwne zasady. :) Nic na to nie poradzę. Dzięki za link Unxutils.
— mutelogan,

https://devcentral.f5.com/blogs/us/unix-to-powershell-tail demonstruje czystą implementację PoSH tego.
— Jewgienij

Nie trzeba używać Select-Object: Get-Content [filename] -last 10i dodać -taildla -f
— MortenB

Odpowiedzi:


492

Użyj -waitparametru z Get-Content, który wyświetla linie w miarę ich dodawania do pliku. Ta funkcja była obecna w PowerShell v1, ale z jakiegoś powodu nie została dobrze udokumentowana w v2.

Oto przykład

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

Po uruchomieniu zaktualizuj i zapisz plik, a zobaczysz zmiany na konsoli.


16
Ciekawy. Myślałbym, że wszystkie istniejące argumenty pojawiają się również w pomocy, ale man gc -par waitmówi mi, że nie ma parametru. Myślę jednak, że to nie rozwiązuje problemu PO, ponieważ o to prosili tail, tail -fa także skutecznego wdrożenia. Ponieważ ten odczytuje również cały plik przed zwróceniem ostatnich wierszy, jest to bolesne dla oczekiwanych rozmiarów plików.
— Joey,

5
Do Twojej dyspozycji jest to implementacja Get-FileTail (alias tail) w PSCX. Jeśli jesteś ciekawy, możesz zajrzeć do kodu źródłowego: pscx.codeplex.com/SourceControl/changeset/view/78514#1358075
— Keith Hill,

7
@Joey -Wait to parametr dynamiczny, który dotyczy tylko dostawcy FileSystem. Z GC można korzystać na dowolnym dostawcy, który implementuje ten interfejs API. Jedynym sposobem poza dokumentacją, którą znam, aby je odkryć, jest użycie (gcm Get-Content) .Parametry z odpowiedniej ścieżki dostawcy. Nie używaj aliasu „gc”, ponieważ parametry dynamiczne nie pojawią się.
— JasonMArcher,

11
Wiem, że to było dawno temu, ale wymaga to procesu zapisu do pliku, aby go otworzyć, dołączyć, zamknąć, zanim Get-Content zadziała. Jeśli proces zapisu nigdy nie zamyka pliku, nie będzie on działał, co nie ma miejsca w przypadku tail -f.
— David Newcomb

15
Dziwnie, -Czekaj pokazuje mi nowe linie tylko wtedy, gdy uzyskuję dostęp do pliku dziennika w jakiś sposób (na przykład wybierając go w Eksploratorze Windows). Tail zapewnia aktualizacje, gdy nowe wiersze są zapisywane w moim pliku. Za pomocą opcji -Wait mogę pozostawić otwarte okno programu PowerShell bez pokazywania nowych wierszy podczas zapisywania pliku. Jeśli następnie wyskoczę i kliknę plik w Eksploratorze Windows, nagle program PowerShell „budzi się” i przechwytuje pozostałe linie. Czy to błąd?
— JoshL

197

Dla kompletności wspomnę, że Powershell 3.0 ma teraz flagę -Tail na Get-Content

Get-Content ./log.log -Tail 10

pobiera ostatnie 10 linii pliku

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

pobiera ostatnie 10 wierszy pliku i czeka na więcej

Ponadto, dla tych użytkowników * nix, zauważ, że większość systemów aliasów cat na Get-Content, więc to zwykle działa

cat ./log.log -Tail 10

@LauraLiparulo w jaki sposób to nie działa? Zdecydowanie z niego korzystałem.
— George Mauer,

4
Właśnie go użyłem i zadziałało w tym formacieGet-Content .\test.txt -Wait -Tail 1
— Coops

@LauraLiparulo - Działa również dla mnie:Get-Content -Path .\sync.log -Wait -Tail 10
— elika kohen

Na ISE używałem while ($ true) / sleep i przełączałem się na ten, ale ten blokuje również cały ISE i nie może uruchamiać skryptów na innych kartach. Czy powinienem po prostu rozpocząć nową instancję ISE?
— Teoman shipahi

@Teomanshipahi W jaki sposób -Waitparametr nie działał dla Ciebie?
— George Mauer,

116

Od wersji PowerShell 3.0 cmdlet Get-Content ma parametr -Tail , który powinien pomóc. Zobacz pomoc online biblioteki technet dotyczącą Get-Content.



4
Uwaga dla niektórych - PS 3.0 jest niedostępny dla Windows XP i Vista.
— tjmoore

1
Używam techniki wymienionej przez Dana, ale zapisuję ją w moim profilu $ PROFIL. Otwórz go za pomocą notatnika $ PROFIL. Następnie w dokumencie tekstowym utwórz nową funkcję: function Tail ($ path) {Get-content -tail 15 -path $ path -wait} W ten sposób możesz uzyskać dostęp do funkcji przy każdym uruchomieniu programu PowerShell.
— Jake Nelson

To powinna być zaakceptowana odpowiedź. - Flaga czekania wymieniona w aktualnie akceptowanej odpowiedzi już nie działa.
— Abdullah Leghari,

21

Użyłem niektórych z podanych tutaj odpowiedzi, ale tylko na pierwszy rzut oka

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

po chwili przeżuje pamięć. Kolega zostawił taki „ogon” w ciągu ostatniego dnia i wzrósł do 800 MB. Nie wiem, czy ogon uniksowy zachowuje się w ten sam sposób (ale wątpię w to). Dlatego dobrze jest używać do krótkoterminowych aplikacji, ale bądź ostrożny.


18

Rozszerzenia społeczności programu PowerShell (PSCX) zapewniają polecenie Get-FileTailcmdlet . Wygląda na odpowiednie rozwiązanie do tego zadania. Uwaga: nie próbowałem tego z bardzo dużymi plikami, ale opis mówi, że skutecznie ogona zawartości i jest przeznaczony do dużych plików dziennika.

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
W obecnej wersji jest błąd, który jest naprawiany w codziennych bitach. Poleciłbym pobrać najnowsze bity i skompilować je przynajmniej do czasu wydania zaktualizowanej wersji.
— Keith Hill,

7
Wersja 2.0 potrzebuje wieków, aby wyświetlić 10 ostatnich wierszy pliku csv o pojemności 1 GB i inaczej Get-Content [filename] | Select-Object -Last 10nie można go przerwać
— Jader Dias

15

Kilka dodatków do poprzednich odpowiedzi. Istnieją zdefiniowane aliasy dla Get-Content, na przykład jeśli jesteś przyzwyczajony do systemu UNIX, który może ci się spodobać cat, a także istnieją typei gc. Więc zamiast

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

Możesz pisać

# 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

Korzystając z Powershell V2 i niższych, get-content czyta cały plik, więc nie przydało mi się to. Poniższy kod działa w przypadku tego, czego potrzebowałem, chociaż prawdopodobnie występują pewne problemy z kodowaniem znaków. Jest to efektywnie tail -f, ale można go łatwo zmodyfikować, aby uzyskać ostatnie x bajtów lub ostatnie x linii, jeśli chcesz szukać podziałów linii wstecz.

$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
}

Znalazłem większość kodu, aby to zrobić tutaj .


1
Czy to prawda, że ​​Get-Content z opcją -Tail czyta cały plik? W przypadku dużych plików wydaje mi się to w porządku.
— Govert,

Myślę, że to zależy od wersji PS. Zaktualizowałem odpowiedź. Utknąłem na serwerze bez możliwości instalowania czegokolwiek w tym czasie, więc powyższy kod był przydatny.
— hajamie 17.04.15

3

Wziąłem rozwiązanie @ hajamie i zapakowałem je w nieco wygodniejsze opakowanie skryptu.

Dodałem opcję, aby zacząć od przesunięcia przed końcem pliku, abyś mógł skorzystać z podobnej do ogona funkcji odczytu pewnej ilości z końca pliku. Uwaga: przesunięcie jest w bajtach, a nie w liniach.

Istnieje również opcja kontynuowania oczekiwania na więcej treści.

Przykłady (zakładając, że zapisujesz to jako 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

A oto sam skrypt ...

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

Bardzo prosty, ale robi to, czego potrzebujesz, bez żadnych modułów dodatkowych lub wymagań wersji PS:

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


4
To brutalne w przypadku dużych plików.
— Pecos Bill

Moje obejście: while($true) { Clear-Host; Get-Content <filename> -tail 40; sleep 1 }:)
— NoLifeKing

0

Prawdopodobnie za późno na odpowiedź, ale spróbuj tego

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

0

Było wiele poprawnych odpowiedzi, jednak żadna z nich nie ma takiej samej składni jak tail w systemie Linux . Poniższa funkcja może być przechowywana w twoim serwerze w $Home\Documents\PowerShell\Microsoft.PowerShell_profile.ps1celu zachowania trwałości ( więcej informacji znajduje się w dokumentacji profili programu PowerShell ).

To pozwala dzwonić ...

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

co jest bardzo zbliżone do składni linuksowej.

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
    }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.