Powershell эквивалент амперсанда bash (&) для разветвления / запуска фоновых процессов

В bash амперсанд (&) можно использовать для запуска команды в фоновом режиме и возврата интерактивного управления пользователю до завершения выполнения команды. Есть ли эквивалентный способ сделать это в Powershell?

Пример использования в bash:

 sleep 30 &

person eddiegroves    schedule 09.10.2008    source источник


Ответы (7)


Если команда является исполняемым файлом или файлом, с которым связан исполняемый файл, используйте Start-Process (доступно в версии 2):

Start-Process -NoNewWindow ping google.com

Вы также можете добавить это как функцию в свой профиль:

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

а затем призыв становится:

bg ping google.com

На мой взгляд, Start-Job - это излишек для простого варианта использования процесса в фоновом режиме:

  1. Start-Job не имеет доступа к вашей существующей области (потому что он выполняется в отдельном сеансе). Вы не можете выполнить "Start-Job {notepad $ myfile}"
  2. Start-Job не сохраняет текущий каталог (потому что он выполняется в отдельном сеансе). Вы не можете выполнить «Start-Job {notepad myfile.txt}», если myfile.txt находится в текущем каталоге.
  3. Вывод не отображается автоматически. Вам нужно запустить Receive-Job с идентификатором задания в качестве параметра.

ПРИМЕЧАНИЕ. Что касается вашего первоначального примера, то «bg sleep 30» не будет работать, потому что sleep - это командлет Powershell. Start-Process работает только тогда, когда вы фактически разветвляете процесс.

person Bogdan Calmac    schedule 05.12.2012
comment
Рад, что нашел этот ответ. Я искал эквивалент механизма двойного разветвления Unix. Мне кажется, что что-то, начатое с Start-Job, будет убито при выходе из оболочки PS. Напротив, кажется, что что-то, начатое с Start-Process, продолжит работать после выхода из оболочки PS. Это основное отличие. - person peterh; 08.11.2013
comment
Да - если вы запустите сценарий с помощью Start-Process, он переживет завершение работы оболочки, но если вы запустили его из окна консоли, он останется привязанным к этому окну, и закрытие окна завершит процесс. - person Guss; 10.08.2015
comment
Однако обратите внимание, что вы не можете выполнять перенаправление вывода с помощью Start-Process, поэтому это НЕ будет работать: Start-Process {ping -n 1000 example.com > ping__example.com.txt }. То же самое с Start-Job работает нормально (хотя вы должны использовать полный путь к выходному файлу). - person Nux; 03.03.2016
comment
Попытка сделать это, чтобы запустить веб-сервер узла, и процесс завершается, когда я выхожу из PowerShell. Кто-нибудь знает почему? - person Jel; 20.10.2016
comment
@Jel Нет, но об этом говорится в комментарии Гусса. - person jpaugh; 07.02.2017
comment
Желаю, чтобы со скриптами работало. Подожди, я кое-что понял. - person js2010; 02.01.2019
comment
start-process powershell -NoNewWindow -ArgumentList '-file. \ loop.ps1' - person js2010; 02.01.2019
comment
Я предполагаю, что первая строка означает, что я не могу использовать ее для командлетов? - person Gert van den Berg; 26.04.2019
comment
Если вам также нужен PID - например, Linux для бедняков тайм-аут $x = Start-Process -Filepath "ping" -ArgumentList 'google.com -n 100' -NoNewWindow -PassThru; Start-Sleep -Seconds 5; try { Stop-Process -Id $x.Id -ErrorAction stop } catch {}; Это будет пинговать в течение 5 секунд, а затем убить процесс, если он все еще запущен. Если вам нужно досрочное завершение, вы можете изменить Start-Sleep на цикл, который вместо этого продолжается или прерывается. - person BrianHVB; 18.12.2019
comment
Запустив -NoNewWindow, вы можете увидеть начальный путь программы. Используйте @args вместо $args, как Богдан написал в своем ответе, потому что вам нужен строковый аргумент, а не объект! - person Timo; 28.10.2020

Начиная с PowerShell Core 6.0 вы можете писать & в конце команды, и это будет эквивалентно запуску конвейера в фоновом режиме в текущем рабочем каталоге.

Это не эквивалент & в bash, это просто более удобный синтаксис для текущей оболочки PowerShell вакансии. Он возвращает объект задания, поэтому вы можете использовать все остальные команды, которые вы использовали бы для заданий. Например 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>

Если вы хотите выполнить пару операторов в фоновом режиме, вы можете объединить _ 5_ оператор вызова, _ 6_ блок сценария и этот новый _ 7_ фоновый оператор, как здесь:

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

Вот еще немного информации со страниц документации:

из Что нового в PowerShell Core 6.0:

Поддержка фоновой обработки конвейеров с помощью амперсанда (&) (# 3360)

Если поместить & в конец конвейера, конвейер будет запущен как задание PowerShell. Когда конвейер находится в фоновом режиме, возвращается объект задания. Когда конвейер запущен как задание, все стандартные *-Job командлеты можно использовать для управления этим заданием. Переменные (без учета переменных, зависящих от процесса), используемые в конвейере, автоматически копируются в задание, поэтому 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 does. Это означает, что вы можете использовать Receive-Job и Remove-Job так же, как если бы вы использовали Start-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 -Name pwsh &
Remove-Job $job

Для получения дополнительной информации о заданиях PowerShell см. about_Jobs.

person Mariusz Pawelski    schedule 22.12.2018
comment
Спасибо за это прекрасное резюме, которое не удалось выполнить сотням страниц MS. - person not2qubit; 02.02.2019
comment
Есть идеи, как обрабатывать задания console? Я попробовал описанное выше с Receive-Job 3, но ничего не вышло. - person not2qubit; 02.02.2019
comment
@ not2qubit Я не совсем понимаю, что вы имеете в виду под консольными заданиями. Какую команду вы запускаете, которую хотите запустить в фоновом режиме? - person Mariusz Pawelski; 06.02.2019
comment
Я использовал приложение, которое запускает консоль Windows, но я не могу получить никаких результатов и надеялся получить его аналогично nix world fg для переноса задания на * передний план. - person not2qubit; 06.02.2019
comment
@ not2qubit К сожалению, похоже, что в powershell нет такой вещи, как unix fg :( Помню, искал, но ничего не нашел - person Mariusz Pawelski; 06.02.2019

Похоже, что блок сценария, переданный в Start-Job, не выполняется в том же текущем каталоге, что и команда Start-Job, поэтому при необходимости обязательно укажите полный путь.

Например:

Start-Job { C:\absolute\path\to\command.exe --afileparameter C:\absolute\path\to\file.txt }
person Gian Marco    schedule 07.07.2012
comment
Так, например, если мне нужно запустить Git Pull в командной строке, мне нужно указать полный путь ко всему ...? Это действительно раздражает. - person CMCDragonkai; 22.04.2014
comment
спасибо, отличный совет, работал с работой, которая не выполнялась, вот почему. - person Omni; 29.05.2015
comment
@CMCDragonkai или просто выполните Start-Job {cd C: \ Path \ To \ Repo; git pull} - person Mahomedalid; 10.05.2018

ps2> start-job {start-sleep 20}

я еще не понял, как получить stdout в реальном времени, start-job требует, чтобы вы опросили stdout с помощью get-job

обновление: я не мог начать работу, чтобы легко делать то, что я хочу, что в основном является оператором bash &. вот мой лучший хак до сих пор

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
person Dustin Getz    schedule 23.06.2011
comment
Начиная с PowerShell v3.0, вы можете получить стандартный вывод в реальном времени следующим образом: Start-Job { Write-Output 'Hello world' } | Receive-Job -Wait - person JamesQMurphy; 08.12.2014

Вы можете использовать командлеты заданий PowerShell для достижения своих целей.

В PowerShell доступно 6 командлетов, связанных с заданиями.

  • Get-Job
    • 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
  • Remove-Job
    • Deletes a Windows PowerShell background job
  • Start-Job
    • Starts a Windows PowerShell background job
  • Stop-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

Если это интересно, вы можете загрузить образец Как создать фоновое задание в PowerShell.

person Eric    schedule 09.11.2016
comment
Хороший ответ, поскольку он касается Powershell 3+. В чем разница между командлетами заданий и предыдущими ответами? - person Jeremy Hajek; 01.01.2017

Вы можете сделать что-то подобное.

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

И если вы хотите его дождаться:

$a | wait-process

Бонусная версия osx или linux:

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

Пример скрипта пингера у меня есть. Аргументы передаются в виде массива:

$1 = start -n powershell pinger,comp001 -pa
person js2010    schedule 10.07.2019
comment
start разветвит процесс и вернет управление вызывающей стороне. Дополнительная информация здесь - person Aethalides; 07.10.2019
comment
@Aethalides start на самом деле является псевдонимом для start-process в PowerShell. - person js2010; 07.10.2019

Я использовал описанное здесь решение http://jtruher.spaces.live.com/blog/cns!7143DA6E51A2628D!130.entry успешно в PowerShell v1.0. В PowerShell v2.0 точно будет проще.

person Jeffery Hicks    schedule 09.10.2008