Get-Content -wait无法按照文档中的说明进行操作

时间:2013-11-12 01:17:10

标签: powershell powershell-v3.0

我注意到当Get-Content path/to/logfile -Wait时,输出实际上每秒都没有刷新,因为文档说明它应该。如果我将Windows资源管理器转到日志文件所在的文件夹并刷新文件夹,则Get-Content会将最新更改输出到日志文件。

如果我在同一个日志文件上尝试使用cygwin tail -f(与尝试get-content时不同的话),那么就像人们期望的那样尝试尾巴,让我不必在不做的情况下刷新实时任何东西。

有谁知道为什么会这样?

5 个答案:

答案 0 :(得分:21)

编辑 BernhardKönig在评论中报告说,这最终已在Powershell 5中得到修复。

你是对的。 -Wait上的Get-Content选项等待文件关闭,然后才能读取更多内容。可以在Powershell中证明这一点,但是可以很难将其作为循环来实现,例如:

while (1){
get-date | add-content c:\tesetfiles\test1.txt 
Start-Sleep -Milliseconds 500
}

每次循环都会打开和关闭输出文件。

要演示此问题,请打开两个Powershell窗口(或ISE中的两个选项卡)。在一个输入此命令:

PS C:\> 1..30 | % { "${_}: Write $(Get-Date -Format "hh:mm:ss")"; start-sleep 1 } >C:\temp\t.txt

每秒会在文件中写入1行30秒,但每次都不会关闭并打开文件。

在另一个窗口中使用Get-Content来读取文件:

get-content c:\temp\t.txt -tail 1 -wait | % { "$_ read at $(Get-Date -Format "hh:mm:ss")" }

使用-Wait选项,您需要使用 Ctrl + C 来停止命令,以便在每次执行命令后等待几秒钟运行该命令3次前三个和更长的等待后,第三个给了我这个输出:

PS C:\> get-content c:\temp\t.txt -tail 1 -wait | % { "$_ read at $(Get-Date -Format "hh:mm:ss")" }
8: Write 12:15:09 read at 12:15:09

PS C:\> get-content c:\temp\t.txt -tail 1 -wait | % { "$_ read at $(Get-Date -Format "hh:mm:ss")" }
13: Write 12:15:14 read at 12:15:15

PS C:\> get-content c:\temp\t.txt -tail 1 -wait | % { "$_ read at $(Get-Date -Format "hh:mm:ss")" }
19: Write 12:15:20 read at 12:15:20
20: Write 12:15:21 read at 12:15:32
21: Write 12:15:22 read at 12:15:32
22: Write 12:15:23 read at 12:15:32
23: Write 12:15:24 read at 12:15:32
24: Write 12:15:25 read at 12:15:32
25: Write 12:15:26 read at 12:15:32
26: Write 12:15:27 read at 12:15:32
27: Write 12:15:28 read at 12:15:32
28: Write 12:15:29 read at 12:15:32
29: Write 12:15:30 read at 12:15:32
30: Write 12:15:31 read at 12:15:32

从中我可以清楚地看到:

  1. 每次运行命令时,都会获取写入文件的最新行。即缓存没有问题,也没有需要刷新的缓冲区。
  2. 只读取一行,然后在另一个窗口中运行的命令完成后才会显示其他输出。
  3. 一旦完成,所有待处理的行一起显示。这必须由关闭文件的源程序触发。
  4. 当我在另外两个窗口中运行Get-Content命令重复练习时,一个窗口读取第3行然后等待,另一个窗口读取第6行,因此该行肯定被写入文件。 / p>

    似乎非常确定-Wait选项正在等待文件关闭事件,而不是等待广告1秒。文档错了。

    修改 我应该补充一点,因为Adi Inbar似乎坚持认为我错了,我在这里给出的例子只使用Powershell,因为这似乎最适合Powershell讨论。我还使用Python验证了行为与我描述的完全一样:

    只要应用程序刷新了缓冲区,就会立即通过新的Get-Content -Wait命令读取写入文件的内容。

    使用Get-Content -Wait的Powershell实例不会在正在写入的文件中显示新内容,即使稍后启动的另一个Powershell实例会看到后面的数据。这最终证明了Powershell可以访问数据,并且Get-Content -Wait不会以1秒的间隔进行轮询,而是在下一次查找数据之前等待一些触发事件。

    dir报告的文件大小在添加行时正在更新,因此不是Powershell等待更新目录条目大小的情况。

    当写入文件的过程关闭它时,Get-Content -Wait几乎立即显示新内容。如果它等待数据刷新到磁盘,那么在Windows刷新磁盘缓存之前会有一段延迟。

    @AdiInbar,我担心你不明白Excel保存文件时的作用。仔细看看。如果您正在编辑test.xlsx,则同一文件夹中还有一个隐藏文件~test.xlsx。使用dir ~test.xlsx -hidden | select CreationTime查看创建时间。保存您的文件,现在test.xlsx的创建时间为~test.xlsx。换句话说,保存在Excel中会保存到~文件,然后删除原始文件,将~文件重命名为原始名称并创建新的~文件。那里有很多开场和收场。

    在保存之前,它会让您正在查看的文件处于打开状态,并在该文件打开后,但它是一个不同的文件。我认为Excel过于复杂,无法准确说明触发Get-Content显示新内容的内容,但我确定您误解了它。

答案 1 :(得分:11)

看起来Powershell正在监视文件的Last Modified属性。问题是“出于性能原因”,包含此属性的NTFS元数据为not automatically updated,除非在某些情况下。

一个情况是文件句柄关闭(因此@Duncan's observations)。另一个是直接查询文件的信息,因此问题中提到的Explorer刷新行为。

您可以通过让Powershell使用Get-Content -Wait监控日志并在详细信息视图中的文件夹中打开资源管理器并显示Last Modified列来观察相关性。请注意,Last Modified在文件修改时不会自动更新。

现在在另一个窗口中获取该文件的属性。例如。在命令提示符下,type该文件。或者在同一文件夹中打开另一个资源管理器窗口,然后右键单击该文件并获取其属性(对我来说,只需右键单击即可)。一旦这样做,第一个Explorer窗口将自动更新Last Modified列,Powershell将注意到更新并赶上日志。在Powershell中,触摸LastWriteTime属性就足够了:

(Get-Item file.log).LastWriteTime = (Get-Item file.log).LastWriteTime

(Get-Item file.log).LastWriteTime = Get-Date

所以现在这对我有用了:

Start-Job {
  $f=Get-Item full\path\to\log
  while (1) {
    $f.LastWriteTime = Get-Date
    Start-Sleep -Seconds 10
  }
}
Get-Content path\to\log -Wait

答案 2 :(得分:2)

你能告诉我们如何重现吗?

我可以在一个PS会话上启动此脚本:

get-content c:\testfiles\test1.txt -wait

这是在另一场会议中:

while (1){
get-date | add-content c:\tesetfiles\test1.txt 
Start-Sleep -Milliseconds 500
}

我看到新条目写在第一个会话中。

答案 3 :(得分:1)

看来get-content仅在通过windows api时才有效,并且附加到文件的版本不同。

program.exe > output.txt

然后

get-content output.txt -wait

不会更新。但是

program.exe | add-content output.txt

可以使用。

get-content output.txt -wait    

所以我猜这取决于应用程序的输出方式。

答案 4 :(得分:1)

我在尝试实时观看WindowsUpdate.log时遇到了同样的问题。虽然不理想,但下面的代码允许我监控进度。 - 由于上面讨论的相同文件写入限制,等待没有工作。

显示最后10行,休眠10秒,清除屏幕,然后再次显示最后10行。 CTRL + C停止流。

def splitLine(ax, x, y, splitNum, style1, style2):
    '''Creates a two styled line given;
    ax = an axis
    x  = an array of x coordinates for 2D Line
    y  = an array of y coordinates for 2D Line
    splitNum = index number to split Line by x tick
    style1 = dictionary for left part of Line
    style2 = dictionary for right part of Line
    '''
    split = x[splitNum]
    low_mask = x <= split
    upper_mask = x >= split

    lower, = ax.plot(x[low_mask], y[low_mask], **style1)
    upper, = ax.plot(x[upper_mask], y[upper_mask], **style2)

    return lower, upper


r = getPostData(wall)



earlyLike  = {'color': 'r', 'lw': 1, 'ls': '--'}
agedLike   = {'color': 'r', 'lw': 2, 'ls': '-', 'label': 'Likes'}
earlyShare = {'color': 'b', 'lw': 1, 'ls': '--'}
agedShare  = {'color': 'b', 'lw': 2, 'ls': '-', 'label': 'Shares'}

fig, ax = plt.subplots()

splitLine(ax, np.array(range(LIMIT)), np.array(r['Likes']), 1, earlyLike, agedLike)
splitLine(ax, np.array(range(LIMIT)), np.array(r['Shares']), 1, earlyShare, agedShare)