Bei der Befehls-/Programmausführung in PowerShell gibt es Situationen, in denen die Standardausgabe stoppt (einfriert/hängt). Ich implementierte die Erkennung davon und, in solchen Fällen, das Stoppen und erneute Ausführen des relevanten Programms.
Zum Beispiel ist das Folgende ein PowerShell-Skript, das alle 5 Sekunden den ffmpeg-Befehl ausführt.
ffmpeg -f dshow -i audio="Microphone (USB Microphone)" -y -t 00:00:05 "tmp.mp3"
Beachten Sie, dass diese Einführung eine Stack Overflow-Antwort referenziert.
I need to get the current state of the last line of the command output stream, then if the line remains unchanged (staled/freezing/hanging) over 5 seconds log “warning: the program is freezing. trying to restart…”, then stop the process and re-start the command. command line - Restart the process if its output unchanged in PowerShell - Super User
Der obige Befehl wird 5 Sekunden lang ausgeführt und endet, aber mit einer einfachen Implementierung kann er in einer Schleife fast dauerhaft laufen:
for ($i = 0; $i -gt -1; $i++) {
$date = Get-Date -Format "yyyy-MM-ddTHH-mm-ss"
$dir = "C:\_documents\WindowsPowerShell\data\recording\$($date.Substring(0,4))\$($date.Substring(5,2))\$($date.Substring(8,2))"
$path = "$dir\$($date.Substring(11,2))-$($date.Substring(14,2))-$($date.Substring(17,2)).mp3"
New-Item -ItemType Directory -Force -Path $dir
ffmpeg -f dshow -i audio="Microphone (USB Microphone)" -y -t 00:10:00 -b:a 128k $path
}
Das Problem hierbei ist jedoch, dass Sie für Programme, die während der Ausführung wie oben hängen/einfrieren, einen Mechanismus vorbereiten müssen, der dies automatisch handhaben kann, wenn es passiert.
Wenn dies Linux statt Windows wäre, könnten Sie leicht mit Terminal-Konsolenausgabe und -eingabe interferieren, indem Sie tmux oder screen verwenden, aber für PowerShell unter Windows scheint es nichts so Entwickeltes und für allgemeine Verwendung Geeignetes wie tmux zu geben.
Übrigens behandelt dieser Artikel strikt die Handhabung von “Hängen/Ausgabestopp/Einfrieren”, nicht erzwungene Programmbeendigung. Wenn der Befehl mit einem Fehlercode endet, gibt es andere (einfachere) Implementierungsmethoden.
Zum Beispiel können Sie für Node.js-Programme durch Wrapping des Programmteils wie folgt das Programm erneut ausführen, wenn ein Fehler auftritt und der Befehl endet.
while ($true) {
try {
node .\notify_app\amazon_scrape.js
} catch {
Write-Host "An error occurred: $_"
Write-Host "Restarting the program..."
}
# Optional delay between restarts (in seconds)
Start-Sleep -Seconds 1
}
Für Java ist fast die gleiche Implementierung möglich.
while ($true) {
try {
# Start your Java application using the java -jar command
Start-Process -FilePath "java" -ArgumentList "-jar", $jarPath -NoNewWindow
# Wait for the Java application to finish
Wait-Process -Name "java" -ErrorAction SilentlyContinue
}
catch {
Write-Host "An error occurred: $($_.Exception.Message)"
}
}
Zurück zum Punkt: In PowerShell können Sie durch die Verwendung von Start-Process zum Ausführen von Befehlen und Interferieren mit dem Ausgabeprotokoll dieses Hintergrundprozesses wie folgt notwendige Verarbeitung durchführen.
$log = "C:\_documents\WindowsPowerShell\data\recording\output.log";
$micName = "Microphone (USB Microphone)";
$process = $null;
Function run-ffmpeg {param([string]$Log,[string]$MicName)
$date = Get-Date -Format "yyyy-MM-ddTHH-mm-ss"
$dir = "C:\_documents\WindowsPowerShell\data\recording\$($date.Substring(0,4))\$($date.Substring(5,2))\$($date.Substring(8,2))"
$path = "$dir\$($date.Substring(11,2))-$($date.Substring(14,2))-$($date.Substring(17,2)).mp3"
New-Item -ItemType Directory -Force -Path $dir
Write-Host "Saving to file path: $path";
$ffmpegCommand = "ffmpeg -f dshow -i audio='$MicName' -y -t 00:10:00 -b:a 128k $path 2>> $Log"
$process = Start-Process powershell -ArgumentList "-NoProfile -ExecutionPolicy Bypass -Command $($ffmpegCommand)" -WindowStyle Hidden -PassThru;
Write-Host "Process ID: $($process.Id)";
# Stop-Process -Id $process.Id
Start-Sleep -Seconds 4;
logchecks $Log;
};
Function tail {Get-Content -Path $args[0] -Tail 1};
Function check {tail $args[0]};
Function logchecks {
do {
$checklog = check $args[0];
Start-Sleep -Seconds 5;
$rechecklog = check $args[0];
if ($checklog -eq $rechecklog) {
$message = "Restarting triggered. [reason: the last line of the log file has not changed after 5 seconds]";
Write-Host $message;
Write-Host "Stopping process with ID: $($process.Id)";
# json, {type: "separator", date: date, message: message}
$now = Get-Date -Format "yyyy-MM-ddTHH-mm-ss";
Write-Output "{`"type`":`"separator`",`"date`":`"$now`",`"message`":`"$message`"}" 2>&1 | Tee-Object -FilePath $Log -Append
# try to prevent the program from being quit
try {
Stop-Process -Id $process.Id;
} catch {
Write-Host "Process with ID: $($process.Id) has already been stopped";
}
}
} while ($checklog -ne $rechecklog)
run-ffmpeg -Log $log -MicName $micName;
};
logchecks $log;
Der Ausführungsablauf des obigen Skripts ist wie folgt:
- Das anfängliche run-ffmpeg wird von der logchecks-Funktion ausgeführt
- Die run-ffmpeg-Funktion führt den ffmpeg-Befehl aus und leitet die Standardausgabe in eine Datei um
- Die logchecks-Funktion überprüft alle 5 Sekunden die letzte Zeile des Ausgabeprotokolls. Wenn es keine Änderung von vor 5 Sekunden gibt, wird festgestellt, dass es eingefroren ist, der Hintergrundprozess, der den ffmpeg-Befehl ausführt, gestoppt und die run-ffmpeg-Funktion erneut ausgeführt. Wenn es eine Änderung gibt, wird nach 5 Sekunden erneut überprüft und derselbe Prozess wiederholt.
Dies ermöglicht die Handhabung, wenn das Protokoll einfriert.