ChatGPT解决这个技术问题 Extra ChatGPT

Powershell equivalent of bash ampersand (&) for forking/running background processes

In bash the ampersand (&) can be used to run a command in the background and return interactive control to the user before the command has finished running. Is there an equivalent method of doing this in Powershell?

Example of usage in bash:

 sleep 30 &

B
Bogdan Calmac

As long as the command is an executable or a file that has an associated executable, use Start-Process (available from v2):

Start-Process -NoNewWindow ping google.com

You can also add this as a function in your profile:

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

and then the invocation becomes:

bg ping google.com

In my opinion, Start-Job is an overkill for the simple use case of running a process in the background:

Start-Job does not have access to your existing scope (because it runs in a separate session). You cannot do "Start-Job {notepad $myfile}" Start-Job does not preserve the current directory (because it runs in a separate session). You cannot do "Start-Job {notepad myfile.txt}" where myfile.txt is in the current directory. The output is not displayed automatically. You need to run Receive-Job with the ID of the job as parameter.

NOTE: Regarding your initial example, "bg sleep 30" would not work because sleep is a Powershell commandlet. Start-Process only works when you actually fork a process.


Glad I found this answer. I was looking for the equivalent of a Unix fork-twice mechanism. To me it seems that something started with Start-Job will be killed when the PS shell exits. In contrast it seems that something started with Start-Process will continue to run after the PS shell exits. This is a major difference.
Yes - if you start a script using Start-Process, it will survive the shell termination, but if you started it from a console window then it stays bound to that window and closing the window will terminate the process.
Note however that you cannot do output redirection with Start-Process and so this will NOT work: Start-Process {ping -n 1000 example.com > ping__example.com.txt }. Same thing with Start-Job works fine (though you have to use full path to the output file).
Attempted to do this to run a node web server, and the process terminates when I exit powershell. Anyone know why?
@Jel No, but Guss's comment talks about that.
M
Mariusz Pawelski

From PowerShell Core 6.0 you are able to write & at end of command and it will be equivalent to running you pipeline in background in current working directory.

It's not equivalent to & in bash, it's just a nicer syntax for current PowerShell jobs feature. It returns a job object so you can use all other command that you would use for jobs. For example 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>

If you want to execute couple of statements in background you can combine & call operator, { } script block and this new & background operator like here:

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

Here's some more info from documentation pages:

from What's New in PowerShell Core 6.0:

Support backgrounding of pipelines with ampersand (&) (#3360) Putting & at the end of a pipeline causes the pipeline to be run as a PowerShell job. When a pipeline is backgrounded, a job object is returned. Once the pipeline is running as a job, all of the standard *-Job cmdlets can be used to manage the job. Variables (ignoring process-specific variables) used in the pipeline are automatically copied to the job so Copy-Item $foo $bar & just works. The job is also run in the current directory instead of the user's home directory. For more information about PowerShell jobs, see about_Jobs.

from about_operators / Ampersand background operator &:

Ampersand background operator & Runs the pipeline before it in a PowerShell job. The ampersand background operator acts similarly to the UNIX "ampersand operator" which famously runs the command before it as a background process. The ampersand background operator is built on top of PowerShell jobs so it shares a lot of functionality with Start-Job. The following command contains basic usage of the ampersand background operator. Get-Process -Name pwsh & This is functionally equivalent to the following usage of Start-Job. Start-Job -ScriptBlock {Get-Process -Name pwsh} Since it's functionally equivalent to using Start-Job, the ampersand background operator returns a Job object just like Start-Job does. This means that you are able to use Receive-Job and Remove-Job just as you would if you had used Start-Job to start the job. $job = Get-Process -Name pwsh & Receive-Job $job Output 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 -Name pwsh & Remove-Job $job For more information on PowerShell jobs, see about_Jobs.


Thanks for this great summary that 100's of MS pages couldn't accomplish.
Any idea how to handle console jobs? I tried the above with Receive-Job 3, but nothing happens.
@not2qubit I'm not sure what you mean by "console jobs". What command do you run that you want to run in background?
I was using an app that launches a windows console, but I can not get any output and was hoping to get it similarly to the nix world fg for bringing job to the *foreground.
@not2qubit Unfortunately it seems that there is no such thing similar to unix fg in powershell :( I remember looking for it, but couldn't find anything
G
Gian Marco

Seems that the script block passed to Start-Job is not executed with the same current directory as the Start-Job command, so make sure to specify fully qualified path if needed.

For example:

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

So for example if I need to run Git Pull in the commandline, I need to specify the full path to everything...? That's really annoying.
thanks, great tip, been going around with a job that wouldn't run, this was the reason why.
@CMCDragonkai or you can do just Start-Job { cd C:\Path\To\Repo ; git pull }
D
Dustin Getz
ps2> start-job {start-sleep 20}

i have not yet figured out how to get stdout in realtime, start-job requires you to poll stdout with get-job

update: i couldn't start-job to easily do what i want which is basically the bash & operator. here's my best hack so far

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

As of PowerShell v3.0 you can get stdout in realtime like this: Start-Job { Write-Output 'Hello world' } | Receive-Job -Wait
E
Eric

You can use PowerShell job cmdlets to achieve your goals.

There are 6 job related cmdlets available in PowerShell.

Get-Job Gets Windows PowerShell background jobs that are running in the current session

Gets Windows PowerShell background jobs that are running in the current session

Receive-Job Gets the results of the Windows PowerShell background jobs in the current session

Gets the results of the Windows PowerShell background jobs in the current session

Remove-Job Deletes a Windows PowerShell background job

Deletes a Windows PowerShell background job

Start-Job Starts a Windows PowerShell background job

Starts a Windows PowerShell background job

Stop-Job Stops a Windows PowerShell background job

Stops a Windows PowerShell background job

Wait-Job Suppresses the command prompt until one or all of the Windows PowerShell background jobs running in the session are complete

Suppresses the command prompt until one or all of the Windows PowerShell background jobs running in the session are complete

If interesting about it, you can download the sample How to create background job in PowerShell


Good answer as it deals with Powershell 3+. What is the difference between job cmdlets and the previous answers?
e
evandrix

You can do something like this.

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

And if you want to wait for it:

$a | wait-process

Bonus osx or linux version:

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

Example pinger script I have. The args are passed as an array:

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

start will fork the process and return control to the caller. More info here
@Aethalides start is actually an alias for start-process in powershell.
b
bence of outer space

tl;dr

Start-Process powershell { sleep 30 }

J
Jeffery Hicks

I've used the solution described here http://jtruher.spaces.live.com/blog/cns!7143DA6E51A2628D!130.entry successfully in PowerShell v1.0. It definitely will be easier in PowerShell v2.0.