Get-Content path/to/logfile -Wait
、ドキュメントで説明されているとおり、出力は実際には毎秒更新されません。 Windowsエクスプローラでログファイルがあるフォルダに移動し、フォルダを更新すると、Get-Content
は、最新の変更をログファイルに出力します。
tail -f
cygwinで同じログファイルに(同時にではなくget-content
)、それは期待どおりにテールし、私が何もしなくてもリアルタイムで更新されます。
なぜこれが起こるのか誰かが知っていますか?
編集:BernhardKönigは、これがPowershell 5で最終的に修正されたとコメントで報告しています
たしかにそれは正しいね。 -Wait
のGet-Content
オプションは、ファイルが閉じられるまで待機してから、さらにコンテンツを読み取ります。これをPowershellで説明することは可能ですが、次のようなループとして正しく実行するのは難しい場合があります。
while (1){
get-date | add-content c:\tesetfiles\test1.txt
Start-Sleep -Milliseconds 500
}
ループを回るたびに出力ファイルを開いて閉じます。
この問題を説明するには、2つのPowershellウィンドウ(またはISEの2つのタブ)を開きます。次のコマンドを入力します。
PS C:\> 1..30 | % { "${_}: Write $(Get-Date -Format "hh:mm:ss")"; start-sleep 1 } >C:\temp\t.txt
これは30秒間実行され、毎秒1行がファイルに書き込まれますが、毎回ファイルを閉じたり開いたりすることはありません。
別のウィンドウでGet-Content
を使用してファイルを読み取ります。
get-content c:\temp\t.txt -tail 1 -wait | % { "$_ read at $(Get-Date -Format "hh:mm:ss")" }
-Wait
オプションを使用すると、 Ctrl+C コマンドを停止して、コマンドを3回実行して、最初の2つのそれぞれの数秒後に数秒待機し、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
これから私ははっきりと見ることができます:
また、他の2つのウィンドウでGet-Content
コマンドを実行して演習を繰り返したとき、1つのウィンドウが3行目を読み取り、もう1つのウィンドウが6行目を待ったため、その行は確実にファイルに書き込まれています。
-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
をトリガーして新しいコンテンツを表示するのかを正確に説明することはできないと思いますが、誤って解釈したと思います。
PowershellがファイルのLast Modified
プロパティを監視しているようです。問題は、「パフォーマンス上の理由から」このプロパティを含むNTFSメタデータが 自動的に更新されない であることです。
1つの状況は、ファイルハンドルが閉じられたときです(つまり @ Duncanの観測 )。もう1つは、ファイルの情報が直接照会されるため、質問で言及されているエクスプローラーの更新動作です。
PowershellでGet-Content -Wait
を使用してログを監視し、エクスプローラーをLast Modified
列が表示されている詳細ビューのフォルダーで開くことで、相関関係を確認できます。ファイルが変更されても、Last Modified
は自動的に更新されないことに注意してください。
別のウィンドウでファイルのプロパティを取得します。例えば。コマンドプロンプトで、type
ファイル。または、同じフォルダで別のエクスプローラウィンドウを開き、ファイルを右クリックしてそのプロパティを取得します(私にとっては、右クリックで十分です)。これを行うとすぐに、最初のエクスプローラーウィンドウが自動的に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
それを再現する方法を教えていただけますか?
このスクリプトを1つのPSセッションで開始できます。
get-content c:\testfiles\test1.txt -wait
そしてこれは別のセッションで:
while (1){
get-date | add-content c:\tesetfiles\test1.txt
Start-Sleep -Milliseconds 500
}
そして、最初のセッションで新しいエントリが書き込まれているのがわかります。
WindowsUpdate.logをリアルタイムで見ようとしたときに、同じ問題が発生しました。理想的ではありませんが、以下のコードで進行状況を監視できました。 -上記と同じファイル書き込み制限のため、待機は機能しませんでした。
最後の10行を表示し、10秒間スリープし、画面をクリアしてから、最後の10行を再び表示します。 CTRL + Cでストリームを停止します。
while(1){
Get-Content C:\Windows\WindowsUpdate.log -tail 10
Start-Sleep -Seconds 10
Clear
}
Get-contentは、Windows APIを通過する場合にのみ機能し、ファイルへの追加のバージョンが異なるようです。
program.exe > output.txt
その後
get-content output.txt -wait
更新されません。だが
program.exe | add-content output.txt
で動作します。
get-content output.txt -wait
したがって、アプリケーションがどのように出力するかによって異なります。