Команда Unix tail эквивалентная в Windows Powershell

350

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

http://tailforwin32.sourceforge.net/

и

Get-Content [имя файла] | Выбор объекта -Последний 10

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

mutelogan
источник
2
Как мы можем узнать, будет ли вам разрешено использовать то, что мы предлагаем, если вы не скажете, почему вам не разрешено использовать первый вариант?
Гейб
3
По какой-либо причине вы не можете использовать tailкоманду, указанную в sourceforge.net/projects/unxutils/files/unxutils/current/… ?
Гейб
1
это на производственной машине, где мне не разрешили копировать любые внешние исполняемые файлы. Некоторые странные политики. :) Не могу с этим поделать. Спасибо за ссылку Unxutils.
mutelogan
https://devcentral.f5.com/blogs/us/unix-to-powershell-tail демонстрирует чистую реализацию этого в PoSH.
Евгений
Не нужно использовать Select-Object: Get-Content [filename] -last 10и добавить -tailдля -f
MortenB

Ответы:

493

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

Вот пример

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

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

ravikanth
источник
16
Интересный. Я бы подумал, что все существующие аргументы также появляются в справке, но man gc -par waitговорит мне, что нет параметра. Но я думаю, что это не решает проблему, с которой сталкивается ОП, поскольку они просили об этом tail, а также tail -fи эффективную реализацию. Поскольку этот файл также читает весь файл перед возвратом последних строк, это болезненно для ожидаемых размеров файлов.
Джои
5
Кстати, это то, что реализация Get-FileTail (псевдоним хвост) делает в PSCX. Если вам интересно, вы можете посмотреть исходный код: pscx.codeplex.com/SourceControl/changeset/view/78514#1358075
Кейт Хилл,
7
@Joey -Wait - это динамический параметр, который применяется только к поставщику файловой системы. GC может использоваться на любом поставщике, который реализует этот API. Единственный способ кроме документации, который я знаю, чтобы обнаружить их, это использовать (gcm Get-Content) .Parameters из соответствующего пути провайдера. Не используйте псевдоним "gc", потому что динамические параметры не будут отображаться.
JasonMArcher
11
Я знаю, что это было некоторое время назад, но это требует процесса записи в файл, чтобы открыть, добавить, закрыть его, прежде чем Get-Content будет работать. Если процесс записи никогда не закроет файл, он не будет работать, что не так с tail -f.
Дэвид Ньюкомб
15
Как ни странно, -Wait показывает только новые строки, когда я получаю доступ к файлу журнала каким-либо образом (например, выбирая его в проводнике Windows). Хвост обеспечивает обновления по мере того, как новые строки записываются в мой файл. С помощью -Wait я могу оставить окно PowerShell открытым, без каких-либо новых строк во время записи файла. Если я затем открою и нажму на файл в проводнике Windows, PowerShell неожиданно «проснется» и поймает оставшиеся строки. Это ошибка?
JoshL
199

Для полноты я упомяну, что у 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
Джордж Мауэр
источник
@LauraLiparulo, каким образом это не работает? Я использовал это раньше, определенно.
Джордж Мауэр
4
Я только использовал это, и это работало на месте в этом форматеGet-Content .\test.txt -Wait -Tail 1
Coops
@LauraLiparulo - У меня тоже работает:Get-Content -Path .\sync.log -Wait -Tail 10
Элика Кохен
На ISE я использовал while ($ true) / sleep и переключился на этот, но этот также блокирует весь ISE и не может запускать скрипты на других вкладках. Должен ли я просто начать новый экземпляр ISE?
Теоман Шипахи
@Teomanshipahi Каким образом -Waitпараметр не работает для вас?
Джордж Мауэр
116

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

Дэн Бланшар
источник
1
Ссылка для скачивания здесь - microsoft.com/en-us/download/details.aspx?id=34595 .
Gedrox
4
Примечание для некоторых - PS 3.0 недоступен для Windows XP и Vista.
tjmoore
1
Я использую технику, упомянутую Дэном, но записываю ее в свой $ PROFILE. Откройте его блокнотом $ PROFILE. Затем в текстовом документе создайте новую функцию: function Tail ($ path) {Get-content -tail 15 -path $ path -wait} Таким образом, вы можете получать доступ к функции при каждом запуске PowerShell.
Джейк Нельсон
Это должен быть принятый ответ. - Флаг ожидания, указанный в принятом ответе, больше не работает.
Абдулла Легари
21

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

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

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

Джон Локвуд
источник
18

Расширения сообщества 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.
Роман Кузьмин
источник
1
В текущей версии есть ошибка, которая исправлена ​​в ежедневных битах. Я бы порекомендовал взять последние биты и скомпилировать их, по крайней мере, пока мы не выпустим обновленную версию.
Кит Хилл
7
В версии 2.0 требуются возрасты, чтобы отобразить 10 последних строк CSV-файла объемом 1 ГБ, и в отличие от Get-Content [filename] | Select-Object -Last 10него нельзя прервать его
Jader Dias
15

Просто некоторые дополнения к предыдущим ответам. Есть псевдонимы, определенные для 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

Используя 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
}

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

hajamie
источник
1
Правда ли, что Get-Content с опцией -Tail читает весь файл? На больших файлах это кажется нормальным для меня.
Говерт
Я считаю, что это зависит от версии PS. Я обновил ответ. Я застрял на сервере без возможности установить что-либо в то время, поэтому приведенный выше код был полезен.
хаджами
3

Я взял решение @ 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;
    }
}
Брайан Рейшл
источник
0

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

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

Джесси
источник
4
Это жестоко для больших файлов.
Пекос Билл
Мой обходной путь был: while($true) { Clear-Host; Get-Content <filename> -tail 40; sleep 1 }:)
NoLifeKing
0

Возможно, слишком поздно для ответа, но попробуйте этот

Get-Content <filename> -tail <number of items wanted>
EvosDeMercile
источник
0

Было много правильных ответов, однако ни один из них не имеет такой же синтаксис, как tail в linux . Следующая функция может быть сохранена в вашем $Home\Documents\PowerShell\Microsoft.PowerShell_profile.ps1для постоянства (см. Документацию профилей PowerShell более подробную информацию к ).

Это позволяет вам звонить ...

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

что довольно близко к синтаксису 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
    }
}
Патрик Стальф
источник