Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get-Content -wait not working as described in the documentation

I've noticed that when Get-Content path/to/logfile -Wait, the output is actually not refreshed every second as the documentation explains it should. If I go in Windows Explorer to the folder where the log file is and Refresh the folder, then Get-Content would output the latest changes to the log file.

If I try tail -f with cygwin on the same log file (not at the same time than when trying get-content), then it tails as one would expect, refreshing real time without me having to do anything.

Does anyone have an idea why this happens?

like image 731
julio.g Avatar asked Nov 12 '13 01:11

julio.g


People also ask

How can you get a more detailed help description of a command?

Description. The Get-Help cmdlet displays information about PowerShell concepts and commands, including cmdlets, functions, Common Information Model (CIM) commands, workflows, providers, aliases, and scripts. To get help for a PowerShell cmdlet, type Get-Help followed by the cmdlet name, such as: Get-Help Get-Process .

What does Get-ChildItem do in PowerShell?

Description. The Get-ChildItem cmdlet gets the items in one or more specified locations. If the item is a container, it gets the items inside the container, known as child items. You can use the Recurse parameter to get items in all child containers and use the Depth parameter to limit the number of levels to recurse.

How do you use get item in PowerShell?

The Get-Item cmdlet gets the item at the specified location. It doesn't get the contents of the item at the location unless you use a wildcard character ( * ) to request all the contents of the item. This cmdlet is used by PowerShell providers to navigate through different types of data stores.

What does :: mean in PowerShell?

Static member operator :: To find the static properties and methods of an object, use the Static parameter of the Get-Member cmdlet. The member name may be an expression. PowerShell Copy.


1 Answers

Edit: Bernhard König reports in the comments that this has finally been fixed in Powershell 5.

You are quite right. The -Wait option on Get-Content waits until the file has been closed before it reads more content. It is possible to demonstrate this in Powershell, but can be tricky to get right as loops such as:

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

will open and close the output file every time round the loop.

To demonstrate the issue open two Powershell windows (or two tabs in the ISE). In one enter this command:

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

That will run for 30 seconds writing 1 line into the file each second, but it doesn't close and open the file each time.

In the other window use Get-Content to read the file:

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

With the -Wait option you need to use Ctrl+C to stop the command so running that command 3 times waiting a few seconds after each of the first two and a longer wait after the third gave me this output:

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 

From this I can clearly see:

  1. Each time the command is run it gets the latest line written to the file. i.e. There is no problem with caching and no buffers needing flushed.
  2. Only a single line is read and then no further output appears until the command running in the other window completes.
  3. Once it does complete all of the pending lines appear together. This must have been triggered by the source program closing the file.

Also when I repeated the exercise with the Get-Content command running in two other windows one window read line 3 then just waited, the other window read line 6, so the line is definitely being written to the file.

It seems pretty conclusive that the -Wait option is waiting for a file close event, not waiting for the advertised 1 second. The documentation is wrong.

Edit: I should add, as Adi Inbar seems to insistent that I'm wrong, that the examples I gave here use Powershell only as that seemed most appropriate for a Powershell discussion. I did also verify using Python that the behaviour is exactly as I described:

Content written to a file is readable by a new Get-Content -Wait command immediately provided the application has flushed its buffer.

A Powershell instance using Get-Content -Wait will not display new content in the file that is being written even though another Powershell instance, started later, sees the later data. This proves conclusively that the data is accessible to Powershell and Get-Content -Wait is not polling at 1 second intervals but waiting for some trigger event before it next looks for data.

The size of the file as reported by dir is updating while lines are being added, so it is not a case of Powershell waiting for the directory entry size to be updated.

When the process writing the file closes it, the Get-Content -Wait displays the new content almost instantly. If it were waiting until the data was flushed to disk there would be up to a delay until Windows flushed it's disk cache.

@AdiInbar, I'm afraid you don't understand what Excel does when you save a file. Have a closer look. If you are editing test.xlsx then there is also a hidden file ~test.xlsx in the same folder. Use dir ~test.xlsx -hidden | select CreationTime to see when it was created. Save your file and now test.xlsx will have the creation time from ~test.xlsx. In other words saving in Excel saves to the ~ file then deletes the original, renames the ~ file to the original name and creates a new ~ file. There's a lot of opening and closing going on there.

Before you save it has the file you are looking at open, and after that file is open, but its a different file. I think Excel is too complex a scenario to say exactly what triggers Get-Content to show new content but I'm sure you mis-interpreted it.

like image 127
Duncan Avatar answered Oct 15 '22 22:10

Duncan