Commande équivalente à la queue Unix dans Windows Powershell

349

Je dois regarder les dernières lignes d'un grand fichier (la taille typique est de 500 Mo à 2 Go). Je recherche un équivalent de la commande Unix tailpour Windows Powershell. Quelques alternatives disponibles sur,

http://tailforwin32.sourceforge.net/

et

Get-Content [nom de fichier] | Select-Object -Last 10

Pour moi, il n'est pas autorisé d'utiliser la première alternative, et la deuxième alternative est lente. Quelqu'un connaît-il une implémentation efficace de tail pour PowerShell?

mutelogan
la source
2
Comment pouvons-nous savoir si vous serez autorisé à utiliser ce que nous suggérons si vous ne dites pas pourquoi vous n'êtes pas autorisé à utiliser la première alternative?
Gabe
3
Une raison pour laquelle vous ne pouvez pas utiliser la tailcommande fournie dans sourceforge.net/projects/unxutils/files/unxutils/current/… ?
Gabe
1
c'est dans une machine de production où je n'étais pas autorisé à copier copier des exécutables externes. Certaines politiques étranges. :) Je ne peux pas m'en empêcher. Merci pour le lien Unxutils.
mutelogan
https://devcentral.f5.com/blogs/us/unix-to-powershell-tail montre une implémentation PoSH pure de cela.
Yevgeniy
Pas besoin d'utiliser Select-Object: Get-Content [filename] -last 10et d'ajouter -tailpour -f
MortenB

Réponses:

492

Utilisez le -waitparamètre avec Get-Content, qui affiche les lignes à mesure qu'elles sont ajoutées au fichier. Cette fonctionnalité était présente dans PowerShell v1, mais pour une raison quelconque, elle n'était pas bien documentée dans la v2.

Voici un exemple

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

Une fois que vous avez exécuté cela, mettez à jour et enregistrez le fichier et vous verrez les modifications sur la console.

ravikanth
la source
16
Intéressant. J'aurais pensé que tous les arguments qui existent apparaissent également dans l'aide, mais man gc -par waitme dit qu'il n'y a pas de paramètre. Mais je pense que cela ne résout pas le problème que pose le PO, car ils l'ont demandé tail, non tail -fet une mise en œuvre efficace également. Étant donné que celui-ci lit également le fichier complet avant de renvoyer les dernières lignes, cela est pénible pour les tailles de fichier attendues.
Joey
5
Pour info, c'est ce que fait l'implémentation Get-FileTail (alias tail) dans PSCX. Si vous êtes curieux, vous pouvez consulter le code source: pscx.codeplex.com/SourceControl/changeset/view/78514#1358075
Keith Hill
7
@Joey -Wait est un paramètre dynamique qui ne s'applique qu'au fournisseur FileSystem. GC peut être utilisé sur n'importe quel fournisseur qui implémente cette API. Outre la documentation que je connais, la seule façon de les découvrir est d'utiliser (gcm Get-Content) .Parameters depuis le chemin du fournisseur approprié. N'utilisez pas l'alias "gc" car les paramètres dynamiques ne s'afficheront pas.
JasonMArcher
11
Je sais que c'était il y a un certain temps, mais cela nécessite le processus d'écriture dans le fichier pour l'ouvrir, l'ajouter, le fermer avant que Get-Content fonctionne. Si le processus d'écriture ne ferme jamais le fichier, cela ne fonctionnera pas, ce qui n'est pas le cas avec tail -f.
David Newcomb
15
Curieusement, -Wait ne me montre de nouvelles lignes que lorsque j'accède à un fichier journal d'une manière ou d'une autre (par exemple en le sélectionnant dans l'Explorateur Windows). Tail fournit des mises à jour à mesure que de nouvelles lignes sont écrites dans mon fichier. Avec -Wait, je peux laisser une fenêtre PowerShell ouverte sans afficher de nouvelles lignes pendant l'écriture du fichier. Si je saute puis clique sur le fichier dans l'Explorateur Windows, soudainement PowerShell "se réveille" et rattrape les lignes restantes. Est-ce un bug?
JoshL
198

Pour être complet, je mentionnerai que Powershell 3.0 a maintenant un indicateur -Tail sur Get-Content

Get-Content ./log.log -Tail 10

obtient les 10 dernières lignes du fichier

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

obtient les 10 dernières lignes du fichier et attend plus

En outre, pour les utilisateurs * nix, notez que la plupart des systèmes alias chat à Get-Content, donc ce généralement des œuvres

cat ./log.log -Tail 10
George Mauer
la source
@LauraLiparulo en quoi cela ne fonctionne-t-il pas? Je l'ai déjà utilisé définitivement.
George Mauer
4
Je viens de l'utiliser et cela a fonctionné parfaitement dans ce formatGet-Content .\test.txt -Wait -Tail 1
Coops
@LauraLiparulo - Fonctionne aussi pour moi:Get-Content -Path .\sync.log -Wait -Tail 10
elika kohen
Sur ISE, j'avais l'habitude d'utiliser while ($ true) / sleep et je suis passé à celui-ci, mais celui-ci verrouille également l'intégralité de l'ISE et ne peut pas exécuter de scripts sur d'autres onglets. Dois-je simplement démarrer une nouvelle instance ISE?
Teoman shipahi
@Teomanshipahi De quelle manière le -Waitparamètre n'a-t-il pas fonctionné pour vous?
George Mauer
116

À partir de PowerShell version 3.0, l'applet de commande Get-Content a un paramètre -Tail qui devrait vous aider. Consultez l'aide en ligne de la bibliothèque technet pour Get-Content.

Dan Blanchard
la source
1
Lien à télécharger ici - microsoft.com/en-us/download/details.aspx?id=34595 .
Gedrox
4
Remarque pour certains - PS 3.0 n'est pas disponible pour Windows XP et Vista.
tjmoore
1
J'utilise la technique mentionnée par Dan mais je l'enregistre dans mon $ PROFILE. Ouvrez-le avec le bloc-notes $ PROFILE. Ensuite, dans le document texte, créez une nouvelle fonction: fonction Tail ($ path) {Get-content -tail 15 -path $ path -wait} De cette façon, vous pouvez accéder à la fonction à chaque démarrage de PowerShell.
Jake Nelson
Ce devrait être la réponse acceptée. -Le drapeau d'attente mentionné dans la réponse actuellement acceptée ne fonctionne plus.
Abdullah Leghari
21

J'ai utilisé certaines des réponses données ici, mais juste un avertissement

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

va mâcher la mémoire après un certain temps. Un collègue a laissé une telle "queue" au cours de la dernière journée et elle est passée à 800 Mo. Je ne sais pas si la queue Unix se comporte de la même manière (mais j'en doute). Il est donc très bien d'utiliser pour des applications à court terme, mais soyez prudent avec elle.

John Lockwood
la source
18

Les extensions de communauté PowerShell (PSCX) fournissent l' Get-FileTailapplet de commande . Cela ressemble à une solution adaptée à la tâche. Remarque: je ne l'ai pas essayé avec des fichiers extrêmement volumineux, mais la description indique qu'il contient efficacement le contenu et qu'il est conçu pour les fichiers journaux volumineux.

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.
Roman Kuzmin
la source
1
Il y a un bug dans la version actuelle qui est corrigé dans les bits quotidiens. Je recommanderais de saisir les derniers bits et de les compiler au moins jusqu'à ce qu'une version mise à jour soit publiée.
Keith Hill
7
La version 2.0 prend beaucoup de temps pour afficher les 10 dernières lignes d'un fichier csv de 1 Go, et différemment d' Get-Content [filename] | Select-Object -Last 10elle ne peut pas être abandonnée
Jader Dias
15

Juste quelques ajouts aux réponses précédentes. Il existe des alias définis pour Get-Content, par exemple si vous êtes habitué à UNIX, vous pourriez aimer cat, et il y a aussi typeet gc. Donc au lieu de

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

tu peux écrire

# 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
Mikael Sundberg
la source
3

À l'aide de Powershell V2 et des versions antérieures, get-content lit l'intégralité du fichier, il ne m'a donc pas été utile. Le code suivant fonctionne pour ce dont j'avais besoin, bien qu'il y ait probablement des problèmes avec les encodages de caractères. Il s'agit en fait de tail -f, mais il peut être facilement modifié pour obtenir les derniers x octets ou les dernières x lignes si vous souhaitez rechercher des sauts de ligne en arrière.

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

J'ai trouvé la plupart du code pour le faire ici .

hajamie
la source
1
Est-il vrai que Get-Content avec l'option -Tail lit tout le fichier? Sur les gros fichiers, cela me semble OK.
Govert
Je pense que cela dépend de la version PS. J'ai mis à jour la réponse. J'étais coincé sur un serveur sans pouvoir installer quoi que ce soit à l'époque, donc le code ci-dessus était utile.
hajamie
3

J'ai pris la solution de @ hajamie et l'ai enveloppée dans un wrapper de script légèrement plus pratique.

J'ai ajouté une option pour commencer à partir d'un décalage avant la fin du fichier, afin que vous puissiez utiliser la fonctionnalité de type queue de lecture d'une certaine quantité à partir de la fin du fichier. Notez que le décalage est en octets, pas en lignes.

Il existe également une option pour continuer à attendre plus de contenu.

Exemples (en supposant que vous l'enregistrez sous 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

Et voici le script lui-même ...

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;
    }
}
Brian Reischl
la source
0

Très basique, mais fait ce dont vous avez besoin sans modules supplémentaires ou exigences de version PS:

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

Jesse
la source
4
C'est brutal sur de gros fichiers.
Pecos Bill
Ma solution de contournement était: while($true) { Clear-Host; Get-Content <filename> -tail 40; sleep 1 }:)
NoLifeKing
0

Probablement trop tard pour une réponse mais essayez celle-ci

Get-Content <filename> -tail <number of items wanted>
EvosDeMercile
la source
0

Il y a eu de nombreuses réponses valides, cependant, aucune d'entre elles n'a la même syntaxe que tail dans linux . La fonction suivante peut être stockée dans votre $Home\Documents\PowerShell\Microsoft.PowerShell_profile.ps1pour la persistance (voir la documentation des profils PowerShell pour plus de détails).

Cela vous permet d'appeler ...

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

ce qui est assez proche de la syntaxe 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
    }
}
Patrick Stalph
la source