Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

powershell

People also ask

Can you do bash in PowerShell?

Both PowerShell and Bash shell provides one intelligent command line Interface (CLI) by using their own configuration management tool. PowerShell is similar to Bash. Mostly commands which are used in bash can be used in PowerShell like 'rm', 'ls', 'cp'.

How do I use ampersand in PowerShell?

The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double quotation marks ("&") to pass it as part of a string. How do I wrap the ampersand in quotes without breaking the outer quotes for the Command parameter? Did you try to enclose the url in single quotes?

What is ampersand in PowerShell?

The ampersand tells PowerShell to execute the scriptblock expression. In essence, it's telling PowerShell that the stuff between the curly braces is code and to run it as code. Passing Arguments to Scriptblocks. Like functions, you can pass "parameters" to scriptblocks also known as arguments.

What is the equivalent of && in PowerShell?

The & operator in PowerShell is just the ; or Semicolon. The && operator in PowerShell has to be run as an if statement.


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:

  1. Start-Job does not have access to your existing scope (because it runs in a separate session). You cannot do "Start-Job {notepad $myfile}"
  2. 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.
  3. 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.


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.


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 }

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