“ Write-Host”,“ Write-Output” หรือ“ [console] :: WriteLine” ต่างกันอย่างไร?


193

มีหลายวิธีในการส่งข้อความ เป็นความแตกต่างที่มีประสิทธิภาพระหว่างการแสดงผลผ่านทางบางสิ่งบางอย่างอะไรWrite-Host, Write-Outputหรือ[console]::WriteLine?

ฉันยังสังเกตเห็นว่าถ้าฉันใช้:

write-host "count=" + $count

ที่+ได้รับรวมอยู่ในการส่งออก ทำไมเป็นอย่างนั้น? ไม่ควรประเมินนิพจน์เพื่อสร้างสตริงที่ต่อกันก่อนที่จะถูกเขียนออกมา?


4
Write-Outputเมื่อคุณเปล่งผลลัพธ์ Write-Hostเมื่อคุณเปล่งข้อมูลการบันทึก [console]::writeline()ไม่เคยใช้งาน
JohnL

2
@JohnL ทำไมเราไม่ควรใช้ [console] :: writeline ()
David Klempfner

3
@Backwards_Dave เนื่องจากคุณมีโฮสต์การเขียน .... ตกลงฉันอาจรู้สึกว่ามันแสดงหน้าต่างคอนโซลใหม่ (มันค่อนข้างนานมาแล้ว) แต่นั่นไม่ได้เกิดขึ้น แต่ยังคงความเป็นจริงว่ามันไม่ได้เป็น PowerShell สำนวนและมีอะไรที่คุณสามารถทำอะไรกับเป็นว่าคุณไม่สามารถทำอะไรกับ[console]::writeline("hello world") Write-Host "hello world"อีกคำตอบที่ดีกว่านี้คือคำว่าwrite-hostwraps write-informationดังนั้นข้อมูลจะถูกนำไปสตรีมอย่างwrite-errorนั้นคุณจึงสามารถจับภาพและใช้ที่อื่นได้ [console]::writeline()ไม่ทำอย่างนั้น
JohnL

คำตอบ:


268

Write-Outputควรใช้เมื่อคุณต้องการส่งข้อมูลในบรรทัดไปป์ แต่ไม่จำเป็นต้องแสดงข้อมูลบนหน้าจอ ไปป์ไลน์จะเขียนลงในที่สุดout-defaultหากไม่มีสิ่งอื่นใดใช้ก่อน

Write-Host ควรใช้เมื่อคุณต้องการทำสิ่งที่ตรงกันข้าม

[console]::WriteLineโดยพื้นฐานแล้วสิ่งที่Write-Hostทำอยู่เบื้องหลัง

เรียกใช้รหัสการสาธิตนี้และตรวจสอบผลลัพธ์

function Test-Output {
    Write-Output "Hello World"
}

function Test-Output2 {
    Write-Host "Hello World" -foreground Green
}

function Receive-Output {
    process { Write-Host $_ -foreground Yellow }
}

#Output piped to another function, not displayed in first.
Test-Output | Receive-Output

#Output not piped to 2nd function, only displayed in first.
Test-Output2 | Receive-Output 

#Pipeline sends to Out-Default at the end.
Test-Output 

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

write-host ("count=" + $count)
# or
write-host "count=$count"

BTW - ดูวิดีโอของ Jeffrey Snover นี้เพื่ออธิบายการทำงานของไปป์ไลน์ ย้อนกลับไปเมื่อฉันเริ่มเรียนรู้ PowerShell ฉันพบว่านี่เป็นคำอธิบายที่มีประโยชน์ที่สุดสำหรับวิธีการทำงานของไปป์ไลน์


ใน Azure WebJob [คอนโซล] :: WriteLine ทำงาน แต่ Write-Host จะทำให้เกิดข้อผิดพลาด: ข้อผิดพลาดภายใน Win32 "ตัวจัดการไม่ถูกต้อง" 0x6 เกิดขึ้นขณะตั้งค่าแอตทริบิวต์อักขระสำหรับบัฟเฟอร์เอาต์พุตคอนโซล อย่าถามฉันทำไม
Gil Roitto

ถูกต้องฉันหากฉันผิด แต่ผมเชื่อว่าWrite-Outputเป็นเช่นเริ่มต้นถ้าคุณมี PsObject และคุณเพียงแค่คายมันออกไปหน้าจอโดยการทำเช่นนี้$objectจริง ๆ Write-Output $objectแล้วมันจะทำสิ่งเดียวกันเช่นนี้ อาจคุ้มค่าที่จะกล่าวถึง
Kolob Canyon

1
มีแนวทางใหม่: หลีกเลี่ยงการใช้Write-Outputเมื่อเป็นไปได้ ดูgithub.com/PoshCode/PowerShellPracticeAndStyle/issues/… > ใช้การส่งคืนเมื่อสิ้นสุดการประมวลผลเท่านั้น > หลีกเลี่ยง Write-Output (... ) แต่เมื่อคุณต้องการทำให้เอาต์พุตชัดเจนขึ้นให้กำหนดเอาต์พุตให้กับตัวแปรที่มีชื่อที่เกี่ยวข้อง และวางตัวแปรนั้นไว้บนบรรทัดด้วยตัวมันเองเพื่อส่งสัญญาณเอาต์พุตที่ชัดเจน > Write-Output -NoEnumerate ใช้งานไม่ได้บน PowerShell 6 และใช้งานมา 16 เดือนขึ้นไป - ไม่มีแผนจะแก้ไข โดยสรุป:> อย่าใช้ Write-Output - EVER
Jeroen Wiert Pluimers

28

นอกเหนือจากที่ Andy พูดถึงมีความแตกต่างซึ่งอาจสำคัญ - write-host เขียนโดยตรงไปยังโฮสต์และไม่ส่งคืนสิ่งใดซึ่งหมายความว่าคุณไม่สามารถเปลี่ยนเส้นทางผลลัพธ์เช่นไปยังไฟล์

---- script a.ps1 ----
write-host "hello"

ตอนนี้ทำงานใน PowerShell:

PS> .\a.ps1 > someFile.txt
hello
PS> type someFile.txt
PS>

เท่าที่เห็นคุณไม่สามารถเปลี่ยนเส้นทางพวกเขาเป็นไฟล์ อาจเป็นเรื่องที่น่าแปลกใจสำหรับคนที่ไม่ระวัง

แต่ถ้าเปลี่ยนไปใช้การเขียนออกแทนคุณจะได้รับการเปลี่ยนเส้นทางการทำงานตามที่คาดไว้


เป็นไปได้ที่จะบันทึกเอาท์พุทการเขียนโฮสต์หากคุณใช้ Powershell เริ่มกระบวนการ \ a.ps1 -RedirectStandardOutput somefile.txt มีปัญหาในการเข้ารหัสแม้ว่า (ไฟล์จะอยู่ใน SystemDefaultEncoding)
MKesper

16

นี่เป็นอีกวิธีหนึ่งในการบรรลุผลงานเขียนเทียบเท่า เพียงใส่สตริงของคุณในเครื่องหมายคำพูด:

"count=$count"

คุณสามารถตรวจสอบให้แน่ใจว่าสิ่งนี้ใช้งานได้เหมือนกันกับ Write-Output โดยการรันการทดสอบนี้:

"blah blah" > out.txt

Write-Output "blah blah" > out.txt

Write-Host "blah blah" > out.txt

สองคนแรกจะส่งออก "blah blah" ไปยัง out.txt แต่อันที่สามจะไม่

"help Write-Output" ให้คำแนะนำเกี่ยวกับพฤติกรรมนี้:

โดยทั่วไปแล้ว cmdlet นี้จะใช้ในสคริปต์เพื่อแสดงสตริงและวัตถุอื่น ๆ บนคอนโซล อย่างไรก็ตามเนื่องจากพฤติกรรมเริ่มต้นคือการแสดงวัตถุที่ส่วนท้ายของไปป์ไลน์โดยทั่วไปไม่จำเป็นต้องใช้ cmdlet

ในกรณีนี้สตริงตัวเอง "count = $ count" เป็นวัตถุในตอนท้ายของไปป์ไลน์และจะปรากฏขึ้น


6

สำหรับประเพณีของWrite-Host, PSScriptAnalyzerผลิตวินิจฉัยต่อไปนี้:

หลีกเลี่ยงการใช้Write-Hostเพราะอาจไม่ทำงานในโฮสต์ทั้งหมดไม่ทำงานเมื่อไม่มีโฮสต์และ (ก่อนหน้า PS 5.0) ไม่สามารถระงับจับหรือเปลี่ยนเส้นทางได้ แต่การใช้งานWrite-Output, หรือWrite-VerboseWrite-Information

ดูเอกสารประกอบที่อยู่เบื้องหลังกฎนั้นสำหรับข้อมูลเพิ่มเติม ข้อความที่ตัดตอนมาสำหรับลูกหลาน:

การใช้งานWrite-Hostนั้นหมดกำลังใจอย่างมากเว้นแต่จะใช้คำสั่งกับShowกริยา Showกริยาอย่างชัดเจนหมายความว่า "การแสดงบนหน้าจอโดยไม่มีความเป็นไปได้อื่น ๆ"

คำสั่งที่มีShowคำกริยาไม่ได้ใช้การตรวจสอบนี้

Jeffrey Snover มีโพสต์บล็อกWrite-Host พิจารณาว่าเป็นอันตรายซึ่งเขาอ้างว่าWrite-Host นั้นมักจะเป็นสิ่งผิดปกติเนื่องจากมันรบกวนระบบอัตโนมัติและให้คำอธิบายเพิ่มเติมที่อยู่เบื้องหลังการวินิจฉัย


3

จากการทดสอบ Write-Output และ [Console] :: WriteLine () ของฉันทำงานได้ดีกว่า Write-Host

ขึ้นอยู่กับจำนวนข้อความที่คุณต้องใช้ในการเขียนสิ่งนี้อาจมีความสำคัญ

ด้านล่างหากผลการทดสอบ 5 รายการสำหรับการเขียนโฮสต์, การเขียนข้อมูลออกและ [คอนโซล] :: WriteLine ()

จากประสบการณ์ที่ จำกัด ของฉันฉันพบเมื่อทำงานกับข้อมูลประเภทใด ๆ ในโลกแห่งความจริงที่ฉันต้องละทิ้ง cmdlets และไปที่คำสั่งระดับล่างเพื่อรับประสิทธิภาพที่เหมาะสมจากสคริปต์ของฉัน

measure-command {$count = 0; while ($count -lt 1000) { Write-Host "hello"; $count++ }}

1312ms
1651ms
1909ms
1685ms
1788ms


measure-command { $count = 0; while ($count -lt 1000) { Write-Output "hello"; $count++ }}

97ms
105ms
94ms
105ms
98ms


measure-command { $count = 0; while ($count -lt 1000) { [console]::WriteLine("hello"); $count++ }}

158ms
105ms
124ms
99ms
95ms

1
Write-OutputและWrite-Hostตอบสนองวัตถุประสงค์ที่แตกต่างกันดังนั้นจึงไม่มีประเด็นในการเปรียบเทียบประสิทธิภาพของพวกเขา ใช่การใช้. NET ประเภทโดยตรงและวิธีการของมันเร็วกว่า แต่คุณพลาดคุณลักษณะระดับสูงที่ PowerShell cmdlet สามารถให้ได้ [Console]::WriteLine()จะคล้ายกับWrite-Hostในกรณีที่อยู่ในมือ แต่จะไม่ทำงานในทุกสถานการณ์เพราะไม่ได้ทุกครอบครัวมี PowerShell คอนโซล
mklement0

0

เกี่ยวกับ [Console] :: WriteLine () - คุณควรใช้มันหากคุณจะใช้ไพพ์ไลน์ใน CMD (ไม่ใช่ PowerShell) สมมติว่าคุณต้องการให้ ps1 สตรีมข้อมูลจำนวนมากไปยัง stdout และยูทิลิตีอื่น ๆ เพื่อใช้ / แปลง หากคุณใช้ Write-Host ในสคริปต์สคริปต์จะช้าลงมาก

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