Команда Unix за еквівалентом хвоста в Windows Powershell


350

Я повинен переглянути останні кілька рядків великого файлу (типовий розмір - 500 МБ-2 ГБ). Я шукаю еквівалент команди Unix tailдля Windows Powershell. Є кілька альтернативних варіантів,

http://tailforwin32.sourceforge.net/

і

Get-Content [ім'я файлу] | Select-Object -Last 10

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


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

Відповіді:


492

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

Ось приклад

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

Після цього запустіть оновлення та збережіть файл, і ви побачите зміни на консолі.


16
Цікаво. Я б міг подумати, що всі аргументи, які існують, також з'являються на допомогу, але man gc -par waitмені кажуть, що немає жодного параметра. Але я думаю, що це не вирішує проблему, яку має ОП, оскільки вони вимагали tail, а не tail -fефективну реалізацію. Оскільки цей також читає весь файл перед поверненням останніх рядків, це болісно для розмірів файлів, які вони очікують.
Joey

5
FYI, саме це робить реалізація Get-FileTail (псевдонім хвіст) у PSCX. Якщо вам цікаво, ви можете подивитися вихідний код: pscx.codeplex.com/SourceControl/changeset/view/78514#1358075
Keith Hill

7
@Joey -Wait - це динамічний параметр, який стосується лише постачальника FileSystem. GC можна використовувати на будь-якому постачальнику, який реалізує цей API. Єдиний спосіб, окрім документації, яку я знаю, це відкрити - використовувати (gcm Get-Content). Параметри зсередини відповідного провайдера. Не використовуйте псевдонім "gc", оскільки динамічні параметри не відображатимуться.
JasonMArcher

11
Я знаю, що це було деякий час тому, але для цього потрібно записати процес у файл, щоб відкрити, додати, закрити його, перш ніж Get-Content запрацює. Якщо процес запису ніколи не закриває файл, він не працюватиме, що не стосується хвоста -f.
Девід Ньюкомб

15
Як не дивно, -Почекайте, коли мені з'являються нові рядки, коли я певним чином отримую доступ до файлу журналу (наприклад, вибравши його в Провіднику Windows). Tail забезпечує оновлення, оскільки в мій файл записуються нові рядки. З-зачекаю, я можу залишити вікно PowerShell щасливо відкритим, не показуючи нових рядків, поки файл записується. Якщо я перескочу і натискаю на файл у Windows Explorer, раптом 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, зверніть увагу , що більшість систем псевдонім кішки для 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
elika kohen

У ISE я використовував час ($ true) / сон і переходив на цей, але цей також блокує весь ISE і не може запускати сценарії на інших вкладках. Чи варто лише запустити новий екземпляр ISE?
Теоман шипахі

@Teomanshipahi Яким чином -Waitпараметр не працював для вас?
Джордж Мауер

116

Як і в версії 3.0 PowerShell, командлет Get-Content має параметр -Tail, який повинен допомогти. Дивіться онлайн-довідку бібліотеки технологій щодо отримання вмісту.


1
Посилання для завантаження тут - microsoft.com/en-us/download/details.aspx?id=34595 .
Гедрокс

4
Примітка для деяких - PS 3.0 недоступний для Windows XP та Vista.
tjmoore

1
Я використовую техніку, згадану Даном, але я записую її у свій $ PROFILE. Відкрийте його за допомогою блокнота $ PROFILE. Потім у текстовому документі створіть нову функцію: функція 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 читає весь файл, тому мені це не дало користі. Наступний код працює для того, що мені було потрібно, хоча, мабуть, є деякі проблеми з кодуваннями символів. Це фактично хвіст -f, але його можна легко змінити, щоб отримати останні х байт або останні х рядків, якщо ви хочете шукати назад для розривів рядків.

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

Я знайшов велику частину коду , щоб зробити це тут .


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>

0

Відповідей було багато, проте жодна з них не має такого ж синтаксису, як хвіст у Linux . Наступну функцію можна зберегти у вашій послідовності ( для отримання детальної інформації $Home\Documents\PowerShell\Microsoft.PowerShell_profile.ps1див. Документацію про профілі оболонок ).

Це дозволяє телефонувати ...

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
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.