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

159

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

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

 sleep 30 &
eddiegroves
источник

Ответы:

126

Пока команда является исполняемым файлом или файлом, имеющим связанный исполняемый файл, используйте Start-Process (доступно из v2):

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 работает только тогда, когда вы фактически разветвляете процесс.

Богдан Кальмак
источник
7
Рад, что нашел этот ответ. Я искал эквивалент Unix-механизма fork-double. Мне кажется, что что-то началось с того, Start-Jobчто будет убит при выходе из оболочки PS. Напротив, кажется, что что-то началось с Start-Processпродолжения работы после выхода из оболочки PS. Это серьезная разница.
Петер
Да - если вы запустите скрипт, используя Start-Processего, он переживет завершение оболочки, но если вы запустили его из окна консоли, он останется привязанным к этому окну, и закрытие окна приведет к завершению процесса.
Гусс
1
Однако обратите внимание , что вы не можете сделать перенаправление вывода с Start-Processи так этого не будет работать: Start-Process {ping -n 1000 example.com > ping__example.com.txt }. То же самое с Start-Jobотлично работает (хотя вы должны использовать полный путь к выходному файлу).
Nux
1
Попытка сделать это для запуска веб-сервера узла, и процесс завершается при выходе из powershell. Кто-нибудь знает почему?
Jel
@Jel Нет, но комментарий Гусса говорит об этом.
jpaugh
26

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

Например:

Start-Job { C:\absolute\path\to\command.exe --afileparameter C:\absolute\path\to\file.txt }
Джан Марко
источник
3
Так, например, если мне нужно запустить Git Pull в командной строке, мне нужно указать полный путь ко всему ...? Это действительно раздражает.
CMCDragonkai
1
спасибо, отличный совет, я работал с работой, которая не работала, вот почему.
Омни
@CMCDragonkai, или вы можете сделать только Start-Job {cd C: \ Path \ To \ Repo; git pull}
Магомедалид
21
ps2> start-job {start-sleep 20}

я еще не понял, как получить стандартный вывод в режиме реального времени, для начала работы требуется опросить стандартный вывод с помощью 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
Дастин Гетц
источник
1
Начиная с PowerShell v3.0, вы можете получить стандартный вывод в реальном времени, например так:Start-Job { Write-Output 'Hello world' } | Receive-Job -Wait
JamesQMurphy
19

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

Это не эквивалентно &в Баше, это просто лучше синтаксис для текущего 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>

Если вы хотите выполнить пару операторов в фоновом режиме, вы можете объединить &оператор вызова , { }блок скрипта и этот новый &оператор фона, как здесь:

& { 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 .

Мариуш Павельски
источник
1
Спасибо за это большое резюме, которое не могли выполнить сотни страниц MS.
not2qubit
Любая идея, как обрабатывать консольные задания? Я попробовал выше с Receive-Job 3, но ничего не происходит.
not2qubit
@ not2qubit Я не уверен, что вы подразумеваете под " консольными заданиями". Какую команду вы запускаете в фоновом режиме?
Мариуш Павельски
Я использовал приложение, которое запускает консоль Windows, но не могу получить никакого вывода и надеялся получить его аналогично миру nix fgдля переноса работы на * передний план .
not2qubit
@ not2qubit К сожалению, похоже, что в PowerShell нет ничего похожего на Unix fg:( Я помню, что искал его, но ничего не смог найти
Мариуш Павельский
17

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

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

  • Найти работу
    • Получает фоновые задания Windows PowerShell, которые выполняются в текущем сеансе
  • Receive-Job
    • Получает результаты фоновых заданий Windows PowerShell в текущем сеансе
  • Remove-Job
    • Удаляет фоновое задание Windows PowerShell.
  • Start-Job
    • Запускает фоновое задание Windows PowerShell
  • Stop-Job
    • Останавливает фоновое задание Windows PowerShell
  • Wait-Job
    • Подавляет командную строку до тех пор, пока одно или все фоновые задания Windows PowerShell, запущенные в сеансе, не будут завершены

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

Эрик
источник
1
Хороший ответ, поскольку он имеет дело с Powershell 3+. В чем разница между командлетами заданий и предыдущими ответами?
Джереми Хайек
3

Вы можете сделать что-то вроде этого.

$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
js2010
источник
start разветвит процесс и вернет управление вызывающей стороне. Более подробная информация здесь
Aethalides
@Aethalides start на самом деле является псевдонимом start-process в powershell.
js2010
2

ТЛ; др

Start-Process powershell { sleep 30 }
забор космоса
источник