ChatGPT解决这个技术问题 Extra ChatGPT

Windows Powershell 中的 Unix 尾部等效命令

我必须查看一个大文件的最后几行(典型大小为 500MB-2GB)。我正在为 Windows Powershell 寻找等效的 Unix 命令 tail。一些可用的替代方案是,

http://tailforwin32.sourceforge.net/

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

对我来说,不允许使用第一种方案,第二种方案很慢。有谁知道 PowerShell 的 tail 的有效实现。

如果您不说明为什么不允许您使用第一种替代方案,我们如何知道您是否可以使用我们的建议?
有什么原因您不能使用 sourceforge.net/projects/unxutils/files/unxutils/current/… 中提供的 tail 命令?
这是在生产机器中,不允许我复制任何外部可执行文件。一些奇怪的政策。 :) 没办法。感谢 Unxutils 链接。
https://devcentral.f5.com/blogs/us/unix-to-powershell-tail 演示了这个的纯 PoSH 实现。
无需使用 Select-Object: Get-Content [filename] -last 10 并添加 -tailfor -f

T
Tony Hinkle

-wait 参数与 Get-Content 一起使用,它会在添加到文件时显示行。此功能存在于 PowerShell v1 中,但由于某种原因在 v2 中没有很好地记录。

这是一个例子

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

运行此程序后,更新并保存文件,您将在控制台上看到更改。


有趣的。我原以为所有存在的参数也会出现在帮助中,但 man gc -par wait 告诉我没有参数。但我认为这并不能解决 OP 所面临的问题,因为他们要求的是 tail,而不是 tail -f 以及一个有效的实现。由于这个文件还在返回最后一行之前读取了完整的文件,这对于他们期望的文件大小来说是很痛苦的。
仅供参考,这就是 PSCX 中的 Get-FileTail(别名 tail)实现。如果您好奇,可以查看源代码:pscx.codeplex.com/SourceControl/changeset/view/78514#1358075
@Joey -Wait 是一个动态参数,仅适用于 FileSystem 提供程序。 GC 可用于任何实现该 API 的提供程序。除了文档之外,我知道发现这些的唯一方法是使用 (gcm Get-Content).Parameters 从适当的提供程序路径中。不要使用别名“gc”,因为动态参数不会显示。
我知道那是不久前的事了,但这需要写入文件的进程在 Get-Content 工作之前打开、附加、关闭它。如果写入过程从不关闭文件,那么它将无法工作,而 tail -f 则不是这样。
奇怪的是, -Wait 仅在我以某种方式访问日志文件时(例如在 Windows 资源管理器中选择它)显示新行。当新行写入我的文件时,Tail 会提供更新。使用 -Wait,我可以愉快地打开一个 PowerShell 窗口,在写入文件时不显示任何新行。如果我然后弹出并单击 Windows 资源管理器中的文件,PowerShell 突然“唤醒”并赶上剩余的行。这是一个错误吗?
s
spyder0077

为了完整起见,我会提到 Powershell 3.0 现在在 Get-Content 上有一个 -Tail 标志

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 这在什么方面不起作用?我以前肯定用过。
我刚刚使用它,它以这种格式运行在现场Get-Content .\test.txt -Wait -Tail 1
@LauraLiparulo - 也适合我:Get-Content -Path .\sync.log -Wait -Tail 10
在 ISE 上,我曾经使用 while($true)/sleep 并切换到这个,但是这个也锁定了整个 ISE,无法在其他选项卡上运行脚本。我应该启动一个新的 ISE 实例吗?
@Teomanshipahi -Wait 参数对您不起作用吗?
D
Dan Blanchard

从 PowerShell 版本 3.0 开始,Get-Content cmdlet 有一个应该有帮助的 -Tail 参数。请参阅the technet library online help for Get-Content.


一些注意事项 - PS 3.0 不适用于 Windows XP 和 Vista。
我使用了 Dan 提到的技术,但我将它记录在我的 $PROFILE 中。用记事本 $PROFILE 打开它。然后在文本文档中,新建一个函数: function Tail ($path) { Get-content -tail 15 -path $path -wait } 这样每次启动 PowerShell 时都可以访问该函数。
这应该是公认的答案。 - 当前接受的答案中提到的等待标志不再起作用。
J
John Lockwood

我使用了这里给出的一些答案,但只是提醒一下

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

一段时间后会咀嚼记忆。一位同事在最后一天留下了这样一个“尾巴”,它上升到了 800 MB。我不知道 Unix tail 的行为是否相同(但我对此表示怀疑)。所以它可以用于短期应用程序,但要小心。


S
StackzOfZtuff

PowerShell Community Extensions (PSCX) 提供 Get-FileTail cmdlet。它看起来是适合该任务的解决方案。注意:我没有尝试使用非常大的文件,但描述说它有效地尾随内容并且它是为大型日志文件设计的。

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.

当前版本中存在一个已在每日位中修复的错误。我建议至少在我们发布更新版本之前获取最新的位并编译它们。
2.0 版需要很长时间才能显示 1GB csv 文件的最后 10 行,并且与 Get-Content [filename] | Select-Object -Last 10 不同,它不能中止
M
Mikael Sundberg

只是对先前答案的一些补充。为 Get-Content 定义了别名,例如,如果您习惯于 UNIX,您可能会喜欢 cat,并且还有 typegc。所以而不是

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

E
EvosDeMercile

答案可能为时已晚,但是,试试这个

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

这些都没有跟随选项。这是使用 tail 命令的 99% 用例。
@Andries 你看到 Ravikanth 的回答了吗?您可以使用 -Wait 进行关注。
添加了@JasonS 建议的标志
h
hajamie

使用 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
}

我找到了大部分代码来执行此操作 here


带有 -Tail 选项的 Get-Content 是否会读取整个文件?在大文件上,对我来说似乎没问题。
我相信这取决于PS版本。我已经更新了答案。我当时被困在无法安装任何东西的服务器上,所以上面的代码很有用。
B
Brian Reischl

我采用了@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;
    }
}

s
starshine wang

试试Windows Server 2003 Resource Kit Tools

它包含一个可以在 Windows 系统上运行的 tail.exe

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


C
Clark Mercer

关于多个文件,我对此主题有一个有用的提示。

使用 PowerShell 5.2(Win7 和 Win10)跟踪单个日志文件(如 Linux 中的“tail -f”)很容易(只需使用“Get-Content MyFile -Tail 1 -Wait”)。但是,一次查看多个日志文件似乎很复杂。但是,使用 PowerShell 7.x+,我发现了一种使用“Foreach-Object -Parrallel”的简单方法。这会同时执行多个“获取内容”命令。例如:

Get-ChildItem C:\logs\*.log | Foreach-Object -Parallel { Get-Content $_ -Tail 1 -Wait }

P
Patrick Stalph

有许多有效的答案,但没有一个具有与 tail in linux 相同的 语法。以下函数可以存储在您的 $Home\Documents\PowerShell\Microsoft.PowerShell_profile.ps1 中以实现持久性(有关更多详细信息,请参阅 powershell profiles documentation)。

这使您可以调用...

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

J
Jesse

非常基本,但无需任何插件模块或 PS 版本要求即可满足您的需求:

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


这对大文件来说是残酷的。
我的解决方法是:while($true) { Clear-Host; Get-Content <filename> -tail 40; sleep 1 } :)
G
George Ogden

可以从此 GitHub 存储库下载为 Windows 编译的所有 UNIX 命令:https://github.com/George-Ogden/UNIX


你好。欢迎来到 SO。在回答一个问题之前,请注意其他 12 个答案,其中 3 个的分数超过 100。