Powershell เทียบเท่ากับ bash ampersand (&) สำหรับการฟอร์ก / การประมวลผลเบื้องหลัง


157

ใน bash แอมเปอร์แซนด์ (&) สามารถใช้เพื่อเรียกใช้คำสั่งในพื้นหลังและส่งคืนการควบคุมแบบโต้ตอบให้กับผู้ใช้ก่อนที่คำสั่งจะทำงานเสร็จสิ้น มีวิธีการที่เท่าเทียมกันในการทำเช่นนี้ใน Powershell หรือไม่?

ตัวอย่างการใช้งานใน bash:

 sleep 30 &

คำตอบ:


123

ตราบใดที่คำสั่งเป็นไฟล์เรียกทำงานหรือไฟล์ที่มีไฟล์ปฏิบัติการที่เกี่ยวข้องให้ใช้กระบวนการเริ่มต้น (พร้อมใช้งานจาก v2):

Start-Process -NoNewWindow ping google.com

คุณยังสามารถเพิ่มสิ่งนี้เป็นฟังก์ชั่นในโปรไฟล์ของคุณ:

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

จากนั้นคำภาวนาจะกลายเป็น:

bg ping google.com

ในความคิดของฉัน, Start-Job เป็น overkill สำหรับกรณีการใช้งานง่าย ๆ ของการเรียกใช้กระบวนการในพื้นหลัง:

  1. งานเริ่มไม่สามารถเข้าถึงขอบเขตที่มีอยู่ของคุณ (เพราะทำงานในเซสชั่นแยกต่างหาก) คุณไม่สามารถทำ "เริ่มงาน {notepad $ myfile}"
  2. งานเริ่มไม่รักษาไดเรกทอรีปัจจุบัน (เพราะทำงานในเซสชั่นที่แยกต่างหาก) คุณไม่สามารถทำ "เริ่มงาน {notepad myfile.txt}" โดยที่ myfile.txt อยู่ในไดเรกทอรีปัจจุบัน
  3. เอาต์พุตจะไม่แสดงขึ้นโดยอัตโนมัติ คุณต้องเรียกใช้ Receive-Job ด้วย ID ของงานเป็นพารามิเตอร์

หมายเหตุ: เกี่ยวกับตัวอย่างเริ่มต้นของคุณ "bg sleep 30" จะไม่ทำงานเนื่องจาก sleep เป็น commandlet Powershell เริ่มกระบวนการทำงานเฉพาะเมื่อคุณแยกกระบวนการจริง ๆ


7
ดีใจที่พบคำตอบนี้ ฉันกำลังมองหากลไกเทียบเท่าของ Unix fork-two สำหรับฉันดูเหมือนว่าบางสิ่งที่เริ่มต้นด้วยStart-Jobจะถูกฆ่าเมื่อเชลล์ PS ออก ในทางตรงกันข้ามดูเหมือนว่าบางสิ่งที่เริ่มต้นด้วยStart-Processจะยังคงทำงานหลังจากที่เชลล์ PS ออก นี่คือความแตกต่างที่สำคัญ
peterh

ใช่ - ถ้าคุณเริ่มต้นสคริปต์โดยใช้Start-Processมันจะรอดจากการยกเลิกเชลล์ แต่ถ้าคุณเริ่มต้นจากหน้าต่างคอนโซลมันจะยังคงถูกผูกไว้กับหน้าต่างนั้นและการปิดหน้าต่างจะยุติกระบวนการ
Guss

1
หมายเหตุ แต่ที่คุณไม่สามารถทำการเปลี่ยนเส้นทางการส่งออกมีStart-Processและอื่น ๆ Start-Process {ping -n 1000 example.com > ping__example.com.txt }นี้จะไม่ทำงาน: สิ่งเดียวกันกับStart-Jobทำงานได้ดี (แม้ว่าคุณจะต้องใช้เส้นทางแบบเต็มไปยังไฟล์ที่ส่งออก)
Nux

1
พยายามทำสิ่งนี้เพื่อเรียกใช้โหนดเว็บเซิร์ฟเวอร์และกระบวนการยุติลงเมื่อฉันออกจาก PowerShell ใครรู้ว่าทำไม
Jel

@Jel No แต่ความเห็นของ Guss พูดถึงเรื่องนั้น
jpaugh

26

ดูเหมือนว่าบล็อกสคริปต์ที่ส่งไปยังStart-Jobจะไม่ถูกเรียกใช้งานด้วยไดเรกทอรีปัจจุบันเดียวกันกับStart-Jobคำสั่งดังนั้นโปรดตรวจสอบให้แน่ใจว่าได้ระบุเส้นทางแบบเต็มหากจำเป็น

ตัวอย่างเช่น:

Start-Job { C:\absolute\path\to\command.exe --afileparameter C:\absolute\path\to\file.txt }

3
ตัวอย่างเช่นถ้าฉันต้องการเรียกใช้ Git Pull ใน commandline ฉันต้องระบุเส้นทางแบบเต็มไปยังทุกอย่าง ... ? มันน่ารำคาญจริงๆ
CMCDragonkai

1
ขอบคุณเคล็ดลับยอดเยี่ยมไปกับงานที่ไม่ได้ทำงานนี่คือเหตุผลว่าทำไม
Omni

@CMCDragonkai หรือคุณสามารถทำได้แค่เริ่มงาน {cd C: \ Path \ To \ Repo; git pull}
Mahomedalid

21
ps2> start-job {start-sleep 20}

ฉันยังไม่ได้คิดวิธีการรับ stdout ในเรียลไทม์เริ่มงานต้องให้คุณสำรวจ stdout กับรับงาน

อัปเดต: ฉันไม่สามารถเริ่มงานทำสิ่งที่ฉันต้องการได้ง่ายๆ นี่คือแฮ็คที่ดีที่สุดของฉันจนถึงตอนนี้

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 คุณจะได้รับ stdout แบบเรียลไทม์เช่นนี้:Start-Job { Write-Output 'Hello world' } | Receive-Job -Wait
JamesQMurphy

19

จาก PowerShell หลัก 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คุณสามารถใช้ cmdlet มาตรฐานทั้งหมดเพื่อจัดการงานได้ ตัวแปร (ไม่สนใจตัวแปรเฉพาะกระบวนการ) ที่ใช้ในไพพ์ไลน์จะถูกคัดลอกไปยังงานโดยอัตโนมัติดังนั้นจึงใช้Copy-Item $foo $bar &งานได้ งานจะถูกเรียกใช้ในไดเรกทอรีปัจจุบันแทนไดเรกทอรีหลักของผู้ใช้ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับงาน PowerShell ดูabout_Jobs

จากabout_operators / เครื่องหมาย & ตัวดำเนินการพื้นหลัง & :

เครื่องหมายตัวดำเนินการพื้นหลังและ

รันขั้นตอนก่อนหน้าในงาน 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 100 หน้าไม่สามารถทำได้
not2qubit

มีความคิดวิธีจัดการงานคอนโซลอย่างไร? ฉันลองข้างต้นด้วยReceive-Job 3แต่ไม่มีอะไรเกิดขึ้น
not2qubit

@ not2qubit ฉันไม่แน่ใจว่าคุณหมายถึงอะไรโดย " งานคอนโซล " คุณรันคำสั่งใดที่คุณต้องการรันในเบื้องหลัง
Mariusz Pawelski

ผมใช้ app ที่เปิดตัวหน้าต่างคอนโซล แต่ฉันไม่สามารถได้รับผลใด ๆ และก็หวังว่าจะได้รับมันคล้าย ๆ กับโลกระวังfgสำหรับการนำงานไปยังส่วนหน้า *
not2qubit

@ not2qubit น่าเสียดายที่ดูเหมือนว่าไม่มีสิ่งใดที่คล้ายกับยูนิกซ์ fgใน PowerShell :( ฉันจำได้ว่ากำลังมองหามัน แต่ไม่สามารถหาอะไรได้เลย
Mariusz Pawelski

17

คุณสามารถใช้งาน PowerShell cmdlets เพื่อให้บรรลุเป้าหมายของคุณ

มี 6 งานที่เกี่ยวข้องกับ cmdlets ใน PowerShell

  • รับงาน
    • รับงานพื้นหลัง Windows PowerShell ที่กำลังทำงานอยู่ในเซสชันปัจจุบัน
  • รับ-Job
    • รับผลลัพธ์ของงานพื้นหลัง Windows PowerShell ในเซสชันปัจจุบัน
  • เอาออกงาน
    • ลบงานพื้นหลัง Windows PowerShell
  • เริ่มต้นอาชีพ
    • เริ่มงานพื้นหลัง Windows PowerShell
  • หยุดงาน
    • หยุดงานพื้นหลัง Windows PowerShell
  • รองาน
    • ไม่แสดงพรอมต์คำสั่งจนกระทั่งงานพื้นหลัง Windows PowerShell หนึ่งงานหรือทั้งหมดทำงานในเซสชันเสร็จสมบูรณ์

หากน่าสนใจคุณสามารถดาวน์โหลดตัวอย่างวิธีสร้างงานพื้นหลังใน PowerShell


1
คำตอบที่ดีเพราะเกี่ยวข้องกับ Powershell 3+ cmdlet ของงานแตกต่างกันกับคำตอบก่อนหน้าคืออะไร?
Jeremy Hajek

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 

ตัวอย่างสคริปต์ pinger ฉันมี args ถูกส่งผ่านเป็นอาร์เรย์:

$1 = start -n powershell pinger,comp001 -pa

start จะแยกกระบวนการและส่งคืนการควบคุมไปยังผู้โทร ข้อมูลเพิ่มเติมได้ที่นี่
Aethalides

@Aethalides start เป็นนามแฝงสำหรับกระบวนการเริ่มต้นใน powershell
js2010


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.