Powershell equivalente de bash ampersand (&) para bifurcar / ejecutar procesos en segundo plano

158

En bash, el ampersand (&) se puede usar para ejecutar un comando en segundo plano y devolver el control interactivo al usuario antes de que el comando haya terminado de ejecutarse. ¿Existe un método equivalente para hacer esto en Powershell?

Ejemplo de uso en bash:

 sleep 30 &
Eddiegroves
fuente

Respuestas:

125

Siempre que el comando sea un ejecutable o un archivo que tenga un ejecutable asociado, use Start-Process (disponible desde v2):

Start-Process -NoNewWindow ping google.com

También puede agregar esto como una función en su perfil:

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

y luego la invocación se convierte en:

bg ping google.com

En mi opinión, Start-Job es una exageración para el caso de uso simple de ejecutar un proceso en segundo plano:

  1. Start-Job no tiene acceso a su alcance existente (porque se ejecuta en una sesión separada). No puede hacer "Start-Job {notepad $ myfile}"
  2. Start-Job no conserva el directorio actual (porque se ejecuta en una sesión separada). No puede hacer "Start-Job {notepad myfile.txt}" donde myfile.txt está en el directorio actual.
  3. La salida no se muestra automáticamente. Debe ejecutar Receive-Job con la ID del trabajo como parámetro.

NOTA: Con respecto a su ejemplo inicial, "bg sleep 30" no funcionaría porque sleep es un comando de Powershell. Start-Process solo funciona cuando realmente bifurcas un proceso.

Bogdan Calmac
fuente
77
Me alegro de haber encontrado esta respuesta. Estaba buscando el equivalente de un mecanismo de horquilla doble de Unix. Para mí, parece que algo con Start-Joblo que comenzó se eliminará cuando se cierre el shell PS. Por el contrario, parece que algo con Start-Processlo que comenzó continuará ejecutándose después de que se cierre el shell PS. Esta es una gran diferencia.
Peter
Sí, si inicia un script usando Start-Process, sobrevivirá a la terminación del shell, pero si lo inició desde una ventana de consola, entonces permanecerá vinculado a esa ventana y cerrar la ventana terminará el proceso.
Guss
1
Nota sin embargo, que no se puede hacer con la redirección de la salida Start-Processy por lo tanto esto no funcionará: Start-Process {ping -n 1000 example.com > ping__example.com.txt }. Lo mismo Start-Jobfunciona bien (aunque debe usar la ruta completa al archivo de salida).
Nux
1
Intenté hacer esto para ejecutar un servidor web de nodo, y el proceso termina cuando salgo de PowerShell. Alguien sabe por qué?
Jel
@Jel No, pero el comentario de Guss habla de eso.
jpaugh
26

Parece que el bloque de script pasado Start-Jobno se ejecuta con el mismo directorio actual que el Start-Jobcomando, así que asegúrese de especificar una ruta completa si es necesario.

Por ejemplo:

Start-Job { C:\absolute\path\to\command.exe --afileparameter C:\absolute\path\to\file.txt }
Gian Marco
fuente
3
Entonces, por ejemplo, si necesito ejecutar Git Pull en la línea de comandos, ¿debo especificar la ruta completa a todo ...? Eso es realmente molesto.
CMCDragonkai
1
gracias, gran consejo, he estado yendo por ahí con un trabajo que no funcionaría, esta fue la razón.
Omni
@CMCDragonkai o puede hacer solo Start-Job {cd C: \ Path \ To \ Repo; git pull}
Mahomedalid
21
ps2> start-job {start-sleep 20}

Todavía no he descubierto cómo obtener stdout en tiempo real, start-job requiere que realice una encuesta stdout con get-job

actualización: no pude iniciar el trabajo para hacer fácilmente lo que quiero, que es básicamente bash & operator. aquí está mi mejor truco hasta ahora

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
Dustin Getz
fuente
1
A partir de PowerShell v3.0 puede obtener la salida estándar en tiempo real como esto:Start-Job { Write-Output 'Hello world' } | Receive-Job -Wait
JamesQMurphy
19

Desde PowerShell Core 6.0 puede escribir &al final del comando y será equivalente a ejecutar su canalización en segundo plano en el directorio de trabajo actual .

No es equivalente a &en bash, es solo una sintaxis más agradable para la función actual de trabajos de PowerShell . Devuelve un objeto de trabajo para que pueda usar todos los demás comandos que usaría para los trabajos. Por ejemplo 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>

Si desea ejecutar un par de declaraciones en segundo plano, puede combinar el &operador de llamada , el { }bloque de script y este nuevo &operador de fondo como aquí:

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

Aquí hay más información de las páginas de documentación:

de Novedades de PowerShell Core 6.0 :

Admite el fondo de las tuberías con ampersand (&) (# 3360)

Poner &al final de una tubería hace que la tubería se ejecute como un trabajo de PowerShell. Cuando una tubería está en segundo plano, se devuelve un objeto de trabajo. Una vez que la canalización se ejecuta como un trabajo, todos los *-Jobcmdlets estándar se pueden usar para administrar el trabajo. Las variables (que ignoran las variables específicas del proceso) utilizadas en la tubería se copian automáticamente en el trabajo, por lo que Copy-Item $foo $bar &simplemente funciona. El trabajo también se ejecuta en el directorio actual en lugar del directorio de inicio del usuario. Para obtener más información sobre los trabajos de PowerShell, consulte about_Jobs .

de about_operators / Ampersand background operator & :

Ampersand operador de fondo y

Ejecuta la canalización antes que en un trabajo de PowerShell. El operador de ampersand en segundo plano actúa de manera similar al "operador de ampersand" de UNIX que ejecuta el comando antes que él como un proceso en segundo plano. El operador en segundo plano está construido sobre los trabajos de PowerShell, por lo que comparte mucha funcionalidad Start-Job. El siguiente comando contiene el uso básico del operador ampersand background.

Get-Process -Name pwsh &

Esto es funcionalmente equivalente al siguiente uso de Start-Job.

Start-Job -ScriptBlock {Get-Process -Name pwsh}

Como es funcionalmente equivalente al uso Start-Job, el operador de fondo y comercial devuelve un Jobobjeto igual que Start-Job does. Esto significa que puede usarlo Receive-Joby Remove-Joblo haría como si lo hubiera hecho Start-Jobpara comenzar el trabajo.

$job = Get-Process -Name pwsh &
Receive-Job $job

Salida

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

Para obtener más información sobre los trabajos de PowerShell, consulte about_Jobs .

Mariusz Pawelski
fuente
1
Gracias por este gran resumen que 100 de las páginas de MS no pudieron lograr.
not2qubit
¿Alguna idea de cómo manejar trabajos de consola ? Intenté lo anterior con Receive-Job 3, pero no pasa nada.
not2qubit
@ not2qubit No estoy seguro de lo que quieres decir con " trabajos de consola ". ¿Qué comando ejecutas que quieres ejecutar en segundo plano?
Mariusz Pawelski
Estaba usando una aplicación que inicia una consola de Windows, pero no puedo obtener ningún resultado y esperaba obtenerla de manera similar al mundo nix fgpara llevar el trabajo al primer plano * .
not2qubit
@ not2qubit Desafortunadamente, parece que no hay tal cosa como unix fgen powershell :( Recuerdo haberlo buscado, pero no pude encontrar nada
Mariusz Pawelski
17

Puede usar los cmdlets de trabajo de PowerShell para lograr sus objetivos.

Hay 6 cmdlets relacionados con el trabajo disponibles en PowerShell.

  • Conseguir trabajo
    • Obtiene trabajos en segundo plano de Windows PowerShell que se ejecutan en la sesión actual
  • Recibir trabajo
    • Obtiene los resultados de los trabajos en segundo plano de Windows PowerShell en la sesión actual
  • Eliminar trabajo
    • Elimina un trabajo en segundo plano de Windows PowerShell
  • Start-Job
    • Inicia un trabajo en segundo plano de Windows PowerShell
  • Stop-Job
    • Detiene un trabajo en segundo plano de Windows PowerShell
  • Esperar trabajo
    • Suprime el símbolo del sistema hasta que se completen uno o todos los trabajos en segundo plano de Windows PowerShell que se ejecutan en la sesión

Si le interesa, puede descargar la muestra Cómo crear un trabajo en segundo plano en PowerShell

Eric
fuente
1
Buena respuesta ya que se trata de Powershell 3+. ¿Cuál es la diferencia entre los cmdlets de trabajo y las respuestas anteriores?
Jeremy Hajek
3

Puedes hacer algo como esto.

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

Y si quieres esperarlo:

$a | wait-process

Versión de bonificación osx o linux:

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

Ejemplo de script pinger que tengo. Los argumentos se pasan como una matriz:

$1 = start -n powershell pinger,comp001 -pa
js2010
fuente
start bifurcará el proceso y devolverá el control a la persona que llama. Más información aquí
Aethalides
@Aethalides start es en realidad un alias para start-process en powershell.
js2010
2

tl; dr

Start-Process powershell { sleep 30 }
ausencia del espacio exterior
fuente