为什么在 powershell 作业中 运行 时 Write-Host 不工作?
Why does Write-Host not work when run in a powershell job?
抱歉,如果我是一个愚蠢的 powershell 新手,但是作业显然无法写入终端有什么问题?我该如何解决?
# test.ps1
function myjob {
Write-Host "Hello, World!" # doesn't show
}
Start-Job -Name MyJob -ScriptBlock ${function:myjob}
Wait-Job MyJob
Remove-Job MyJob
听起来您正在尝试使用 Write-Host
到 直接、同步 从后台作业写入控制台(终端)。
但是,PowerShell jobs do not allow direct access to the caller's console. Any output - even to the PowerShell host (which in foreground use is the console, if run in one) is routed through PowerShell's system of output streams (see the conceptual about_Redirection 帮助主题)。
因此,您总是需要Receive-Job
cmdlet 以便接收来自 PowerShell 作业的输出。
以下 示例接收作业输出 同步 ,即它 阻止执行 直到作业完成 (-Wait
),然后将其删除 (-AutoRemoveJob
);请参阅底部的 异步(轮询、非阻塞)方法。
$null = Start-Job -Name MyJob -ScriptBlock { Write-Host "Hello, World!" }
Receive-Job -Wait -AutoRemoveJob -Name MyJob
注意在工作中重新使用 Write-Host
:
In foreground use, Write-Host
output - 尽管主要设计用于 host (控制台)- 可以通过 信息流 重定向或捕获(其编号为 6
,在 PSv5+ 中可用);例如:
# OK - no output
Write-Host 'silence me' 6>$null
Write-Host
通过(基于子进程的)后台作业 接收到输出 ,但是, 不能 被重定向或捕获,从 PowerShell 7.2.1 开始:
# !! `silence me` still prints.
Start-Job { Write-Host 'silence me' } | Receive-Job -Wait -AutoRemoveJob 6>$null
相比之下,它 可以 是 redirected/captured 当使用(通常更可取)thread-基于后台作业(相对于基于 子进程 的后台作业),通过 Start-ThreadJob
:
# OK - no output
Start-ThreadJob { Write-Host 'silence me' } | Receive-Job -Wait -AutoRemoveJob 6>$null
等待作业以非阻塞方式完成,作业输出可用时传递:
# Start a simple job that writes a "." to the host once a second,
# for 5 seconds
$job = Start-Job $job -ScriptBlock {
1..5| ForEach-Object { Write-Host -NoNewLine .; Start-Sleep 1 }
}
"Waiting for job $($job.Id) to terminate while passing its output through..."
do {
$job | Receive-Job # See if job output is available (non-blocking) and pass it through
Start-Sleep 1 # Do other things or sleep a little.
} while (($job | Get-Job).State -in 'NotStarted', 'Running')
"`nJob terminated with state '$($job.State)'."
$job | Remove-Job # Clean up.
注意:在这个简单的例子中,预期的终止状态是Completed
(没有或只有不-发生终止错误)或Failed
(使用 throw
生成脚本终止错误(并且未在作业中捕获))。
- 有关可能状态的完整列表,请参阅
[System.Management.Automation.JobState]
枚举。
Start-Job
返回的作业 object - 而不是通过 -Name
参数自行选择的名称 - 用于与工作互动。这消除了可能 多个 工作与给定 -Name
一起出现的歧义,所有这些工作都将成为目标。
抱歉,如果我是一个愚蠢的 powershell 新手,但是作业显然无法写入终端有什么问题?我该如何解决?
# test.ps1
function myjob {
Write-Host "Hello, World!" # doesn't show
}
Start-Job -Name MyJob -ScriptBlock ${function:myjob}
Wait-Job MyJob
Remove-Job MyJob
听起来您正在尝试使用 Write-Host
到 直接、同步 从后台作业写入控制台(终端)。
但是,PowerShell jobs do not allow direct access to the caller's console. Any output - even to the PowerShell host (which in foreground use is the console, if run in one) is routed through PowerShell's system of output streams (see the conceptual about_Redirection 帮助主题)。
因此,您总是需要Receive-Job
cmdlet 以便接收来自 PowerShell 作业的输出。
以下 示例接收作业输出 同步 ,即它 阻止执行 直到作业完成 (-Wait
),然后将其删除 (-AutoRemoveJob
);请参阅底部的 异步(轮询、非阻塞)方法。
$null = Start-Job -Name MyJob -ScriptBlock { Write-Host "Hello, World!" }
Receive-Job -Wait -AutoRemoveJob -Name MyJob
注意在工作中重新使用 Write-Host
:
In foreground use,
Write-Host
output - 尽管主要设计用于 host (控制台)- 可以通过 信息流 重定向或捕获(其编号为6
,在 PSv5+ 中可用);例如:# OK - no output Write-Host 'silence me' 6>$null
Write-Host
通过(基于子进程的)后台作业 接收到输出 ,但是, 不能 被重定向或捕获,从 PowerShell 7.2.1 开始:# !! `silence me` still prints. Start-Job { Write-Host 'silence me' } | Receive-Job -Wait -AutoRemoveJob 6>$null
相比之下,它 可以 是 redirected/captured 当使用(通常更可取)thread-基于后台作业(相对于基于 子进程 的后台作业),通过
Start-ThreadJob
:# OK - no output Start-ThreadJob { Write-Host 'silence me' } | Receive-Job -Wait -AutoRemoveJob 6>$null
等待作业以非阻塞方式完成,作业输出可用时传递:
# Start a simple job that writes a "." to the host once a second,
# for 5 seconds
$job = Start-Job $job -ScriptBlock {
1..5| ForEach-Object { Write-Host -NoNewLine .; Start-Sleep 1 }
}
"Waiting for job $($job.Id) to terminate while passing its output through..."
do {
$job | Receive-Job # See if job output is available (non-blocking) and pass it through
Start-Sleep 1 # Do other things or sleep a little.
} while (($job | Get-Job).State -in 'NotStarted', 'Running')
"`nJob terminated with state '$($job.State)'."
$job | Remove-Job # Clean up.
注意:在这个简单的例子中,预期的终止状态是
Completed
(没有或只有不-发生终止错误)或Failed
(使用throw
生成脚本终止错误(并且未在作业中捕获))。- 有关可能状态的完整列表,请参阅
[System.Management.Automation.JobState]
枚举。
- 有关可能状态的完整列表,请参阅
Start-Job
返回的作业 object - 而不是通过-Name
参数自行选择的名称 - 用于与工作互动。这消除了可能 多个 工作与给定-Name
一起出现的歧义,所有这些工作都将成为目标。