Odpowiednik Powershell z bash ampersand (&) do rozwidlania / uruchamiania procesów w tle

157

W bashu znak ampersand (&) może być używany do uruchamiania polecenia w tle i zwracania użytkownikowi interaktywnej kontroli przed zakończeniem działania polecenia. Czy istnieje równoważna metoda zrobienia tego w programie PowerShell?

Przykład użycia w bash:

 sleep 30 &
eddiegroves
źródło

Odpowiedzi:

123

O ile polecenie jest plikiem wykonywalnym lub plikiem, który ma skojarzony plik wykonywalny, użyj Start-Process (dostępne od v2):

Start-Process -NoNewWindow ping google.com

Możesz również dodać to jako funkcję w swoim profilu:

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

a wtedy wezwanie staje się:

bg ping google.com

Moim zdaniem Start-Job jest przesadą w prostym przypadku uruchamiania procesu w tle:

  1. Start-Job nie ma dostępu do istniejącego zakresu (ponieważ działa w osobnej sesji). Nie możesz wykonać „Rozpocznij pracę {notepad $ myfile}”
  2. Start-Job nie zachowuje bieżącego katalogu (ponieważ działa w osobnej sesji). Nie można wykonać „Start-Job {notepad myfile.txt}”, gdzie mojplik.txt znajduje się w bieżącym katalogu.
  3. Dane wyjściowe nie są wyświetlane automatycznie. Musisz uruchomić Receive-Job z identyfikatorem zadania jako parametrem.

UWAGA: Jeśli chodzi o twój początkowy przykład, "bg sleep 30" nie zadziała, ponieważ sleep jest poleceniem Powershell. Start-Process działa tylko wtedy, gdy faktycznie rozwidlisz proces.

Bogdan Calmac
źródło
7
Cieszę się, że znalazłem tę odpowiedź. Szukałem odpowiednika uniksowego mechanizmu podwójnego rozwidlenia. Wydaje mi się, że coś, co zaczęło się od, Start-Jobzostanie zabite, gdy powłoka PS zakończy działanie. Z drugiej strony wydaje się, że coś, co zaczęło się od, Start-Processbędzie nadal działać po zamknięciu powłoki PS. To jest duża różnica.
peterh
Tak - jeśli uruchomisz skrypt za pomocą Start-Process, przetrwa on zakończenie powłoki, ale jeśli uruchomisz go z okna konsoli, pozostanie on powiązany z tym oknem, a zamknięcie okna zakończy proces.
Guss
1
Uwaga jednak, że nie można zrobić przekierowanie z wyjściową Start-Processi tak to nie będzie działać: Start-Process {ping -n 1000 example.com > ping__example.com.txt }. To samo z Start-Jobdziała dobrze (chociaż musisz użyć pełnej ścieżki do pliku wyjściowego).
Nux
1
Próbowałem to zrobić, aby uruchomić serwer WWW węzła, a proces kończy się, gdy wyjdę z PowerShell. Czy ktoś wie, dlaczego?
Jel
@Jel Nie, ale mówi o tym komentarz Gussa.
jpaugh,
26

Wydaje się, że przekazany blok skryptu Start-Jobnie jest wykonywany w tym samym katalogu bieżącym, co Start-Jobpolecenie, więc w razie potrzeby należy podać pełną ścieżkę.

Na przykład:

Start-Job { C:\absolute\path\to\command.exe --afileparameter C:\absolute\path\to\file.txt }
Gian Marco
źródło
3
Na przykład, jeśli muszę uruchomić Git Pull w wierszu poleceń, muszę określić pełną ścieżkę do wszystkiego ...? To naprawdę denerwujące.
CMCDragonkai
1
dzięki, świetna wskazówka, zajmowałem się pracą, która nie mogła zostać uruchomiona, to był powód.
Omni
@CMCDragonkai lub możesz po prostu rozpocząć pracę {cd C: \ Path \ To \ Repo; git pull}
Mahomedalid
21
ps2> start-job {start-sleep 20}

jeszcze nie wymyśliłem, jak uzyskać stdout w czasie rzeczywistym, rozpoczęcie pracy wymaga sondowania stdout za pomocą get-job

aktualizacja: nie mogłem łatwo rozpocząć pracy, aby łatwo robić to, co chcę, czyli w zasadzie operator bash i. oto moja najlepsza jak dotąd 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
Dustin Getz
źródło
1
Począwszy od wersji 3.0 programu PowerShell można uzyskać standardowe wyjście w czasie rzeczywistym w następujący sposób:Start-Job { Write-Output 'Hello world' } | Receive-Job -Wait
JamesQMurphy,
19

Z PowerShell Core 6.0 możesz pisać &na końcu polecenia i będzie to równoważne z uruchomieniem potoku w tle w bieżącym katalogu roboczym .

Nie jest to odpowiednik &w bash, to po prostu ładniejsza składnia dla bieżącej funkcji zadań PowerShell . Zwraca obiekt zadania, więc możesz użyć wszystkich innych poleceń, których używałbyś do zadań. Na przykład 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>

Jeśli chcesz wykonać kilka instrukcji w tle, możesz połączyć &operator wywołania , { }blok skryptu i ten nowy &operator w tle, jak tutaj:

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

Oto więcej informacji ze stron dokumentacji:

z Co nowego w programie PowerShell Core 6.0 :

Obsługa tła potoków za pomocą znaku ampersand (&) (# 3360)

Umieszczenie &na końcu potoku powoduje uruchomienie potoku jako zadania programu PowerShell. Gdy potok działa w tle, zwracany jest obiekt zadania. Gdy potok działa jako zadanie, *-Jobdo zarządzania nim można używać wszystkich standardowych poleceń cmdlet. Zmienne (ignorujące zmienne specyficzne dla procesu) używane w potoku są automatycznie kopiowane do zadania, więc Copy-Item $foo $bar &po prostu działają. Zadanie jest również uruchamiane w bieżącym katalogu zamiast w katalogu osobistym użytkownika. Aby uzyskać więcej informacji na temat zadań programu PowerShell, zobacz about_Jobs .

from about_operators / Ampersand operator w tle & :

Operator tła Ampersand &

Uruchamia potok przed nim w zadaniu programu PowerShell. Operator tła „ampersand” działa podobnie do „operatora ampersand” systemu UNIX, który słynie z uruchamiania polecenia przed nim jako procesu w tle. Operator tła ampersand jest zbudowany na podstawie zadań programu PowerShell, dzięki czemu udostępnia wiele funkcji Start-Job. Następujące polecenie zawiera podstawowe użycie operatora tła ampersand.

Get-Process -Name pwsh &

Jest to funkcjonalnie równoważne następującemu użyciu Start-Job.

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

Ponieważ jest to funkcjonalnie równoważne użyciu Start-Job, operator tła ampersand zwraca Jobobiekt, tak jak Start-Job does. Oznacza to, że możesz używać Receive-Jobi Remove-Jobtak samo, jak gdybyś Start-Jobzaczynał pracę.

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

Wynik

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

Aby uzyskać więcej informacji na temat zadań programu PowerShell, zobacz about_Jobs .

Mariusz Pawelski
źródło
1
Dziękuję za to wspaniałe podsumowanie, którego setki stron MS nie mogły wykonać.
not2qubit
Masz pomysł, jak radzić sobie z zadaniami konsoli ? Wypróbowałem powyższe Receive-Job 3, ale nic się nie dzieje.
not2qubit
@ not2qubit Nie jestem pewien, co masz na myśli, mówiąc o „ zadaniach konsoli ”. Jakie polecenie uruchamiasz, a które chcesz uruchomić w tle?
Mariusz Pawelski
Używałem aplikacji, która uruchamia konsolę systemu Windows, ale nie mogę uzyskać żadnych wyników i miałem nadzieję, że uda mi się uzyskać ją podobnie jak w świecie nix fgza przeniesienie pracy na * pierwszy plan .
not2qubit
@ not2qubit Niestety wygląda na to, że nie ma czegoś podobnego do unixa fgw PowerShell :( Pamiętam, że szukałem, ale nie mogłem nic znaleźć
Mariusz Pawelski
17

Możesz użyć poleceń cmdlet zadań programu PowerShell, aby osiągnąć swoje cele.

W programie PowerShell dostępnych jest 6 poleceń cmdlet związanych z zadaniami.

  • Get-Job
    • Pobiera zadania w tle programu Windows PowerShell, które są uruchomione w bieżącej sesji
  • Odbieranie pracy
    • Pobiera wyniki zadań w tle programu Windows PowerShell w bieżącej sesji
  • Usuń zadanie
    • Usuwa zadanie w tle programu Windows PowerShell
  • Start-Job
    • Uruchamia zadanie w tle programu Windows PowerShell
  • Stop-Job
    • Zatrzymuje zadanie w tle programu Windows PowerShell
  • Wait-Job
    • Pomija wiersz polecenia do momentu zakończenia jednego lub wszystkich zadań w tle programu Windows PowerShell działających w sesji

Jeśli Cię to interesuje, możesz pobrać przykładowy sposób tworzenia zadania w tle w programie PowerShell

Eric
źródło
1
Dobra odpowiedź, ponieważ dotyczy Powershell 3+. Jaka jest różnica między poleceniami cmdlet zadań a poprzednimi odpowiedziami?
Jeremy Hajek
3

Możesz zrobić coś takiego.

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

A jeśli chcesz na to poczekać:

$a | wait-process

Wersja bonusowa na OSX lub Linux:

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

Przykładowy skrypt pinger, który mam. Argumenty są przekazywane jako tablica:

$1 = start -n powershell pinger,comp001 -pa
js2010
źródło
start rozwidli proces i zwróci kontrolę rozmówcy. Więcej informacji tutaj
Aethalides,
@Aethalides start jest w rzeczywistości aliasem dla start-process w PowerShell.
js2010
2

tl; dr

Start-Process powershell { sleep 30 }
zagłębienia przestrzeni kosmicznej
źródło