ChatGPT解决这个技术问题 Extra ChatGPT

用于分叉/运行后台进程的 bash 与号 (&) 等效的 Powershell

在 bash 中,与号 (&) 可用于在后台运行命令,并在命令完成运行之前将交互控制返回给用户。在 Powershell 中是否有等效的方法?

bash 中的用法示例:

 sleep 30 &

B
Bogdan Calmac

只要命令是可执行文件或具有关联可执行文件的文件,请使用 Start-Process(可从 v2 获得):

Start-Process -NoNewWindow ping google.com

您还可以将此作为功能添加到您的个人资料中:

function bg() {Start-Process -NoNewWindow @args}

然后调用变为:

bg ping google.com

在我看来,Start-Job 对于在后台运行进程的简单用例来说是一种过度杀伤:

Start-Job 无权访问您现有的范围(因为它在单独的会话中运行)。您不能执行“Start-Job {notepad $myfile}” Start-Job 不会保留当前目录(因为它在单独的会话中运行)。您不能在 myfile.txt 位于当前目录中的情况下执行“Start-Job {notepad myfile.txt}”。输出不会自动显示。您需要以作业 ID 作为参数运行 Receive-Job。

注意:关于您的初始示例,“bg sleep 30”将不起作用,因为 sleep 是 Powershell 命令行开关。 Start-Process 仅在您实际分叉一个进程时才有效。


很高兴我找到了这个答案。我一直在寻找相当于 Unix fork-twice 的机制。对我来说,似乎以 Start-Job 开头的东西会在 PS shell 退出时被杀死。相反,以 Start-Process 开头的东西似乎会在 PS shell 退出后继续运行。这是一个主要的区别。
是的 - 如果您使用 Start-Process 启动脚本,它将在 shell 终止后继续存在,但如果您从控制台窗口启动它,那么它将保持绑定到该窗口,关闭窗口将终止进程。
但是请注意,您不能使用 Start-Process 进行输出重定向,因此这将不起作用:Start-Process {ping -n 1000 example.com > ping__example.com.txt }。与 Start-Job 相同的东西可以正常工作(尽管您必须使用输出文件的完整路径)。
尝试执行此操作以运行节点 Web 服务器,并且当我退出 powershell 时该进程终止。有谁知道为什么?
@Jel 不,但 Guss 的评论谈到了这一点。
M
Mariusz Pawelski

从 PowerShell Core 6.0 开始,您可以在命令结束时编写 &,这相当于在当前工作目录的后台运行管道

它不等同于 bash 中的 &,它只是当前 PowerShell jobs 功能的更好语法。它返回一个作业对象,因此您可以使用您将用于作业的所有其他命令。例如 Receive-Job

C:\utils> ping google.com &

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command
--     ----            -------------   -----         -----------     --------             -------
35     Job35           BackgroundJob   Running       True            localhost            Microsoft.PowerShell.M...


C:\utils> Receive-Job 35

Pinging google.com [172.217.16.14] with 32 bytes of data:
Reply from 172.217.16.14: bytes=32 time=11ms TTL=55
Reply from 172.217.16.14: bytes=32 time=11ms TTL=55
Reply from 172.217.16.14: bytes=32 time=10ms TTL=55
Reply from 172.217.16.14: bytes=32 time=10ms TTL=55

Ping statistics for 172.217.16.14:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 10ms, Maximum = 11ms, Average = 10ms
C:\utils>

如果您想在后台执行几个语句,您可以组合 & call operator{ } script block 和这个新的 & background operator,如下所示:

& { cd .\SomeDir\; .\SomeLongRunningOperation.bat; cd ..; } &

以下是来自文档页面的更多信息:

来自 What's New in PowerShell Core 6.0

支持使用与号 (&) 对管道进行后台处理 (#3360) 将 & 放在管道的末尾会导致管道作为 PowerShell 作业运行。当管道在后台运行时,将返回一个作业对象。一旦管道作为作业运行,所有标准 *-Job cmdlet 都可用于管理作业。管道中使用的变量(忽略特定于流程的变量)会自动复制到作业中,因此 Copy-Item $foo $bar & 可以正常工作。该作业也在当前目录而不是用户的主目录中运行。有关 PowerShell 作业的详细信息,请参阅 about_Jobs。

来自 about_operators / Ampersand background operator &

& 后台运算符 & 在 PowerShell 作业中运行管道之前的管道。 & 号后台操作符的行为类似于 UNIX“& 号操作符”,后者以后台进程的形式运行之前的命令。 & 号后台运算符构建在 PowerShell 作业之上,因此它与 Start-Job 共享许多功能。以下命令包含 & 后台运算符的基本用法。 Get-Process -Name pwsh & 这在功能上等同于 Start-Job 的以下用法。 Start-Job -ScriptBlock {Get-Process -Name pwsh} 因为它在功能上等同于使用 Start-Job,所以和号背景运算符返回一个 Job 对象,就像 Start-Job 一样。这意味着您可以像使用 Start-Job 启动作业一样使用 Receive-Job 和 Remove-Job。 $job = Get-Process -Name pwsh & Receive-Job $job 输出 NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName ------ ----- ---- - ------ -- -- ----------- 0 0.00 221.16 25.90 6988 988 pwsh 0 0.00 140.12 29.87 14845 845 pwsh 0 0.00 85.51 0.91 19639 988 pwsh $job = Get-Process -命名 pwsh 和 Remove-Job $job 有关 PowerShell 作业的更多信息,请参阅 about_Jobs。


感谢这个伟大的总结,100 的 MS 页面无法完成。
知道如何处理 console 工作吗?我用 Receive-Job 3 尝试了上述方法,但没有任何反应。
@not2qubit 我不确定您所说的“控制台工作”是什么意思。你想在后台运行什么命令?
我正在使用一个启动 Windows 控制台的应用程序,但我无法获得任何输出,并希望获得与 nix 世界fg类似的输出,以便将工作带到*前台
@not2qubit 不幸的是,powershell 中似乎没有类似于 unix fg 的东西 :( 我记得找过,但找不到任何东西
G
Gian Marco

似乎传递给 Start-Job 的脚本块没有使用与 Start-Job 命令相同的当前目录执行,因此请确保在需要时指定完全限定的路径。

例如:

Start-Job { C:\absolute\path\to\command.exe --afileparameter C:\absolute\path\to\file.txt }

因此,例如,如果我需要在命令行中运行 Git Pull,我需要指定所有内容的完整路径...?这真的很烦人。
谢谢,很好的提示,一直在做一份无法运行的工作,这就是原因。
@CMCDragonkai 或者你可以做 Start-Job { cd C:\Path\To\Repo ;混帐拉}
D
Dustin Getz
ps2> start-job {start-sleep 20}

我还没有弄清楚如何实时获取标准输出,开始工作需要你用 get-job 轮询标准输出

更新:我无法开始工作来轻松地做我想做的事,这基本上是 bash & 运算符。到目前为止,这是我最好的 hack

PS> notepad $profile #edit init script -- added these lines
function beep { write-host `a }
function ajp { start powershell {ant java-platform|out-null;beep} } #new window, stderr only, beep when done
function acjp { start powershell {ant clean java-platform|out-null;beep} }
PS> . $profile #re-load profile script
PS> ajp

从 PowerShell v3.0 开始,您可以像这样实时获取标准输出:Start-Job { Write-Output 'Hello world' } | Receive-Job -Wait
E
Eric

您可以使用 PowerShell 作业 cmdlet 来实现您的目标。

PowerShell 中有 6 个与作业相关的 cmdlet。

Get-Job 获取在当前会话中运行的 Windows PowerShell 后台作业

获取在当前会话中运行的 Windows PowerShell 后台作业

Receive-Job 获取当前会话中 Windows PowerShell 后台作业的结果

获取当前会话中 Windows PowerShell 后台作业的结果

Remove-Job 删除 Windows PowerShell 后台作业

删除 Windows PowerShell 后台作业

Start-Job 启动 Windows PowerShell 后台作业

启动 Windows PowerShell 后台作业

Stop-Job 停止 Windows PowerShell 后台作业

停止 Windows PowerShell 后台作业

Wait-Job 抑制命令提示符,直到会话中运行的一个或所有 Windows PowerShell 后台作业完成

禁止命令提示符,直到会话中运行的一个或所有 Windows PowerShell 后台作业完成

如果对此感兴趣,您可以下载示例 How to create background job in PowerShell


很好的答案,因为它处理 Powershell 3+。作业 cmdlet 和之前的答案有什么区别?
e
evandrix

你可以做这样的事情。

$a = start-process -NoNewWindow powershell {timeout 10; 'done'} -PassThru

如果你想等待它:

$a | wait-process

奖励 osx 或 linux 版本:

$a = start-process pwsh '-c',{start-sleep 5; 'done'} -PassThru 

我有示例 pinger 脚本。 args 作为数组传递:

$1 = start -n powershell pinger,comp001 -pa

start 将分叉进程并将控制权返回给调用者。更多信息here
@Aethalides start 实际上是 powershell 中 start-process 的别名。
b
bence of outer space

tl;博士

Start-Process powershell { sleep 30 }

J
Jeffery Hicks

我已经在 PowerShell v1.0 中成功使用了此处描述的解决方案 http://jtruher.spaces.live.com/blog/cns!7143DA6E51A2628D!130.entry。在 PowerShell v2.0 中肯定会更容易。