Команда Unix tail эквивалентная в Windows Powershell - PullRequest
313 голосов
/ 13 декабря 2010

Мне нужно взглянуть на последние несколько строк большого файла (типичный размер 500 МБ-2 ГБ). Я ищу эквивалент Unix команды tail для Windows Powershell. Несколько доступных вариантов:

http://tailforwin32.sourceforge.net/

и

Get-Content [filename] | Select-Object -Last 10

Для меня не разрешено использовать первую альтернативу, а вторая - медленная. Кто-нибудь знает эффективную реализацию хвоста для PowerShell.

Ответы [ 10 ]

440 голосов
/ 13 декабря 2010

Используйте параметр -wait с Get-Content, который отображает строки по мере их добавления в файл.Эта функция присутствовала в PowerShell v1, но по какой-то причине плохо документирована в v2.

Вот пример

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

После запуска обновите и сохраните файл, и высм. изменения на консоли.

159 голосов
/ 21 марта 2013

Для полноты картины упомяну, что Powershell 3.0 теперь имеет флаг -Tail на Get-Content

Get-Content ./log.log -Tail 10

получает последние 10 строк файла

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

получаетпоследние 10 строк файла и ждет больше

Кроме того, для тех * nix пользователей обратите внимание, что большинство систем псевдоним cat для Get-Content, так что обычно это работает

cat ./log.log -Tail 10
113 голосов
/ 31 октября 2012

Начиная с PowerShell версии 3.0, командлет Get-Content имеет параметр -Tail , который должен помочь.См. онлайн-справку библиотеки technet для Get-Content.

21 голосов
/ 23 мая 2016

Я использовал некоторые из приведенных здесь ответов, но только на голову, что

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

через некоторое время будет жевать памятьЗа последний день коллега оставил такой «хвост», и он поднялся до 800 МБ.Я не знаю, ведет ли себя хвост Unix таким же образом (но я сомневаюсь в этом).Так что это хорошо для краткосрочных приложений, но будьте осторожны с этим.

18 голосов
/ 13 декабря 2010

Расширения сообщества PowerShell (PSCX) предоставляет командлет Get-FileTail .Похоже, подходящее решение для задачи.Примечание: я не пробовал его с очень большими файлами, но в описании сказано, что он эффективно подбирает содержимое и предназначен для больших файлов журналов.

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.
15 голосов
/ 08 июня 2015

Просто некоторые дополнения к предыдущим ответам.Для Get-Content определены псевдонимы, например, если вы привыкли к UNIX, вам может потребоваться cat, а также есть type и gc.Таким образом, вместо

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

вы можете написать

# 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 голосов
/ 11 июня 2015

Я взял решение @ hajamie и обернул его в немного более удобную оболочку сценария.

Я добавил опцию, чтобы начать со смещения до конца файла, чтобы вы могли использовать подобную хвосту функцию считывания определенной суммы с конца файла.Обратите внимание, что смещение указывается в байтах, а не в строках.

Также есть возможность продолжить ожидание большего количества контента.

Примеры (при условии, что вы сохраните это как 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

А вот и сам скрипт ...

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;
    }
}
3 голосов
/ 25 марта 2014

Используя Powershell V2 и ниже, get-content читает весь файл, поэтому он мне не пригодился. Следующий код работает для того, что мне нужно, хотя, вероятно, есть некоторые проблемы с кодировкой символов. Это фактически tail -f, но его можно легко изменить, чтобы получить последние x байтов или последние x строк, если вы хотите искать разрывы строк в обратном направлении.

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

Я нашел большую часть кода для этого здесь .

2 голосов
/ 22 ноября 2017

try Windows Server 2003 Resource Kit Tools

содержит tail.exe, который можно запустить в системе Windows.

https://www.microsoft.com/en-us/download/details.aspx?id=17657

1 голос
/ 24 декабря 2013

Очень простой, но делает то, что вам нужно, без каких-либо дополнительных модулей или требований к версии PS:

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

...