วิธีส่งออกบางสิ่งใน PowerShell


210

ฉันกำลังเรียกใช้สคริปต์ PowerShell จากภายในไฟล์แบตช์ สคริปต์จะดึงเว็บเพจและตรวจสอบว่าเนื้อหาของหน้านั้นเป็นสตริง "ตกลง"

สคริปต์ PowerShell ส่งคืนระดับข้อผิดพลาดไปยังสคริปต์ชุดงาน

ชุดสคริปต์ถูกดำเนินการโดยScriptFTPซึ่งเป็นโปรแกรมอัตโนมัติของ FTP หากมีข้อผิดพลาดเกิดขึ้นฉันสามารถให้ ScriptFTP ส่งเอาต์พุตคอนโซลแบบเต็มไปยังผู้ดูแลระบบผ่านทางอีเมล

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

ฉันยังใหม่กับ PowerShell และไม่แน่ใจว่าจะใช้ฟังก์ชันเอาต์พุตใดสำหรับสิ่งนี้ ฉันเห็นสาม:

  • เขียนเป็นเจ้าภาพ
  • เขียนเอาท์พุท
  • เขียนข้อผิดพลาด

สิ่งที่จะเป็นสิ่งที่ถูกต้องเพื่อใช้ในการเขียนไปยังเทียบเท่าของ Windows stdout?

คำตอบ:


196

เพียงแสดงสิ่งที่เป็น PowerShell เป็นเรื่องของความงาม - และหนึ่งในจุดแข็งที่ยิ่งใหญ่ที่สุด ตัวอย่างเช่น Hello, World! แอปพลิเคชันจะลดลงเป็นบรรทัดเดียว:

"Hello, World!"

มันสร้างวัตถุสตริงกำหนดค่าดังกล่าวและเป็นรายการสุดท้ายในไปป์ไลน์คำสั่งที่เรียก.toString()เมธอดและส่งผลลัพธ์ให้กับSTDOUT(โดยค่าเริ่มต้น) เรื่องของความงาม

Write-*คำสั่งอื่น ๆมีความเฉพาะเจาะจงในการแสดงผลข้อความไปยังสตรีมที่เกี่ยวข้องและมีสถานที่เช่นนั้น


9
นั่นไม่ใช่สิ่งที่เกิดขึ้นจริง ๆ มันคือการแสดงออกที่แท้จริงของสตริงและสิ่งเดียวที่อยู่ในท่อ "Hello, World!" | Out-Hostดังนั้นมันจึงเป็นเทียบเท่ากับ Out-Hostในทางกลับกันส่งวัตถุไปยังโฮสต์ PowerShell เพื่อแสดงผลและการใช้งานขึ้นอยู่กับโฮสต์ โฮสต์คอนโซลจะส่งพวกเขาไปที่จุดส่งออกมาตรฐาน (ผ่านOut-Defaultไปตามทาง) แน่นอน PowerShell ISE แสดงในบานหน้าต่างเอาท์พุทอย่างไรก็ตามและโฮสต์อื่น ๆ อาจทำสิ่งอื่นทั้งหมด
Joey

5
วัตถุยังไม่ได้รับการแปลงเป็นสตริงอย่างสุ่มสี่สุ่มห้า แต่ผ่านฟอร์แมตเตอร์ที่ตัดสินใจว่าจะทำอะไรกับมัน นั่นเป็นเหตุผลที่คุณเห็นGet-ChildItemผลลัพธ์ที่ออกมาในรูปแบบตารางตัวอย่างเช่นและผลลัพธ์ที่มีคุณสมบัติหลายอย่าง (เช่น WMI) เป็นค่าเริ่มต้นFormat-Listแทน
Joey

120

ฉันคิดว่าในกรณีนี้คุณจะต้องเขียนออก

หากคุณมีสคริปต์เช่น

Write-Output "test1";
Write-Host "test2";
"test3";

จากนั้นหากคุณโทรหาสคริปต์ด้วยเอาต์พุตที่เปลี่ยนเส้นทางyourscript.ps1 > out.txtคุณจะได้รับtest2บนหน้าจอtest1\ntest3\nใน "out.txt"

โปรดทราบว่า "test3" และบรรทัดส่งออกจะเพิ่มบรรทัดใหม่ต่อท้ายข้อความของคุณเสมอและไม่มีวิธีใดใน PowerShell ที่จะหยุดการทำงานนี้ (นั่นคือecho -nเป็นไปไม่ได้ใน PowerShell ด้วยคำสั่งดั้งเดิม) หากคุณต้องการ (ค่อนข้างพื้นฐานและง่ายในการทุบตี ) การทำงานของecho -nแล้วดูคำตอบของ samthebest

หากไฟล์แบตช์รันคำสั่ง PowerShell จะเป็นไปได้มากที่สุดที่จะจับคำสั่ง Write-Output ฉันมี "การสนทนายาว" กับผู้ดูแลระบบเกี่ยวกับสิ่งที่ควรเขียนลงในคอนโซลและสิ่งที่ไม่ควร ตอนนี้เราได้ตกลงกันแล้วว่าข้อมูลเฉพาะถ้าสคริปต์ดำเนินการสำเร็จหรือตายจะต้องเป็นWrite-Host'ed และทุกอย่างที่เป็นผู้เขียนสคริปต์อาจจำเป็นต้องรู้เกี่ยวกับการดำเนินการ (สิ่งที่รายการได้รับการปรับปรุงสิ่งที่มีการตั้งค่า เพื่อเขียนเอาท์พุท ด้วยวิธีนี้เมื่อคุณส่งสคริปต์ไปยังผู้ดูแลระบบเขาสามารถrunthescript.ps1 >someredirectedoutput.txtดูได้อย่างง่ายดายบนหน้าจอหากทุกอย่างเรียบร้อย จากนั้นส่ง "someredirectedoutout.t.t" กลับไปยังนักพัฒนา


9

ผมคิดว่าต่อไปนี้คือการจัดแสดงที่ดีของก้องกับเขียนโฮสต์ สังเกตว่าการทดสอบ () ส่งคืนอาร์เรย์ int จริง ๆ ไม่ใช่ int เดียวที่จะทำให้เชื่อได้ง่าย

function test {
    Write-Host 123
    echo 456 # AKA 'Write-Output'
    return 789
}

$x = test

Write-Host "x of type '$($x.GetType().name)' = $x"

Write-Host "`$x[0] = $($x[0])"
Write-Host "`$x[1] = $($x[1])"

ขั้วเอาท์พุทข้างต้น:

123
x of type 'Object[]' = 456 789
$x[0] = 456
$x[1] = 789

ฉันสามารถดูที่นี้ทุกวัน ... แต่ทำไม $x = testเพียงพิมพ์123และยังไม่ได้456?
not2qubit

7

คุณสามารถใช้สิ่งเหล่านี้ในสถานการณ์ของคุณเนื่องจากพวกเขาเขียนลงในสตรีมเริ่มต้น (เอาต์พุตและข้อผิดพลาด) หากคุณกำลังไพพ์เอาต์พุตไปยัง commandlet อื่นคุณต้องการใช้Write-Outputซึ่งจะยุติในWrite-Host ในที่สุด

บทความนี้อธิบายถึงตัวเลือกผลลัพธ์ต่าง ๆ : PowerShell O สำหรับเอาท์พุท


1
ขอบคุณสำหรับลิงค์ ความดีนี้จะซับซ้อน ถ้าเขียนโฮสต์เป็นปลายทางหรือฟังก์ชันการล้างข้อมูลฉันจะลองทำตามนั้นและรายงานกลับ
Pekka

3
Write-Host "Found file - " + $File.FullName -ForegroundColor Magenta

Magenta สามารถเป็นหนึ่งในค่าตัวระบุ "System.ConsoleColor" - ดำ, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, เทา, DarkGray, น้ำเงิน, เขียว, แดง, ม่วง, เหลือง, ขาว

+ $File.FullNameเป็นตัวเลือกและแสดงให้เห็นถึงวิธีการวางตัวแปรลงในสตริง


2

คุณไม่สามารถรับ PowerShell เพื่อเลิกบรรทัดใหม่ที่น่ารำคาญ ไม่มีสคริปต์หรือ cmdlet ที่ทำสิ่งนี้

แน่นอน Write-Host ไร้สาระแน่นอนเพราะคุณไม่สามารถเปลี่ยนเส้นทาง / ไพพ์จากมันได้! คุณเพียงแค่ต้องเขียนของคุณเอง:

using System;

namespace WriteToStdout
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args != null)
            {
                Console.Write(string.Join(" ", args));
            }
        }
    }
}

เช่น

PS C:\> writetostdout finally I can write to stdout like echo -n
finally I can write to stdout like echo -nPS C:\>

คุณสามารถทำสิ่งนี้ได้ด้วยตัวเอง [System.Console] :: เขียน ("stringy") อย่างไรก็ตามคุณจะไม่สามารถเปลี่ยนเส้นทางได้เลยใน PowerShell
Nicholi

1
แน่นอนว่าคุณสามารถ ดูคำถามนี้
Slogmeister Extraordinaire

1

สิ่งที่จะเป็นสิ่งที่ถูกต้องที่จะใช้เพื่อเขียนถึงเทียบเท่ากับ stdout ของ Windows?

ในผลแต่มากน่าเสียดายที่ทั้งWindows PowerShell และ PowerShell หลัก ณ v7.0 ส่งทั้งหมดของพวกเขา 6 (!) เอาท์พุทลำธารเพื่อstdoutเมื่อเรียกจากภายนอกผ่านทาง PowerShell ของ CLI

  • ดูปัญหา GitHub นี้เพื่อการสนทนาเกี่ยวกับพฤติกรรมที่เป็นปัญหาซึ่งน่าจะไม่ได้รับการแก้ไขเพื่อความเข้ากันได้แบบย้อนหลัง

  • ในทางปฏิบัติหมายความว่าสตรีม PowerShell ใดก็ตามที่คุณส่งเอาต์พุตไปจะถูกมองว่าเป็นเอาต์พุตstdoutโดยผู้เรียกภายนอก:

    • ตัวอย่างเช่นหากคุณเรียกใช้สิ่งต่อไปนี้cmd.exeคุณจะไม่เห็นผลลัพธ์เนื่องจากการเปลี่ยนเส้นทาง stdout เพื่อNULใช้กับสตรีม PowerShell ทั้งหมด:

      • C:\>powershell -noprofile -command "Write-Error error!" >NUL
    • อย่างไรก็ตาม - อยากรู้อยากเห็น - ถ้าคุณเปลี่ยนเส้นทาง stderr , PowerShell จะส่งกระแสข้อมูลข้อผิดพลาดของมันไปยัง stderrเพื่อที่2>คุณจะสามารถจับเอาท์พุทกระแสข้อผิดพลาดแบบเลือก; เอาต์พุตต่อไปนี้เป็นเพียงเอาต์พุต'hi'ความสำเร็จในขณะที่จับเอาต์พุตข้อผิดพลาดในไฟล์err.txt:

      • C:\>powershell -noprofile -command "'hi'; Write-Error error!" 2>err.txt

ที่น่าพอใจพฤติกรรมคือ

  • ส่ง PowerShell ของกระแสออกความสำเร็จ (จำนวน1) เพื่อ stdout
  • ส่งเอาต์พุตจากสตรีมอื่นทั้งหมดไปยังstderrซึ่งเป็นตัวเลือกเดียวเนื่องจากระหว่างกระบวนการมีเพียง2สตรีมเอาต์พุต - stdout (เอาต์พุตมาตรฐาน) สำหรับข้อมูลและ stderr (ข้อผิดพลาดมาตรฐาน) สำหรับข้อความแสดงข้อผิดพลาดและข้อความประเภทอื่น ๆ ทั้งหมด - เช่น เป็นข้อมูลสถานะ - ที่ไม่ได้ข้อมูล

  • ขอแนะนำให้แยกความแตกต่างนี้ในรหัสของคุณแม้ว่าจะไม่ได้รับการเคารพในขณะนี้


ภายใน PowerShell :

  • Write-Hostคือสำหรับการแสดงผลการส่งออกและทะลุกระแสออกความสำเร็จ - เช่นผลผลิตของตนไม่สามารถ (โดยตรง) บันทึกในตัวแปรหรือระงับหรือเปลี่ยนเส้นทาง

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

    • เนื่องจากไม่สามารถจับหรือเปลี่ยนเส้นทางก่อนหน้านี้ PowerShell เวอร์ชัน 5 ได้ทำWrite-Hostกับสตรีมข้อมูลที่แนะนำใหม่(หมายเลข6) ดังนั้นจึงเป็นไปได้ที่จะสามารถจับภาพและเปลี่ยนเส้นทางWrite-Hostเอาต์พุตได้

  • Write-Errorมีไว้สำหรับการเขียนข้อผิดพลาดที่ไม่สิ้นสุดลงในสตรีมข้อผิดพลาด (หมายเลข2); ในเชิงแนวคิดกระแสข้อผิดพลาดเทียบเท่า stderr

  • Write-Outputเขียนถึงความสำเร็จ [output] stream (number 1) ซึ่งเทียบเท่ากับแนวคิดในการ stdout; มันเป็นกระแสการเขียนข้อมูล (ผลลัพธ์) ถึง

    • อย่างไรก็ตามไม่ค่อยจำเป็นต้องใช้งานอย่างชัดเจนWrite-Outputเนื่องจากคุณสมบัติเอาท์พุทโดยนัยของ PowerShell :
      • ผลลัพธ์จากคำสั่งใด ๆ หรือการแสดงออกที่ไม่ได้บันทึกอย่างชัดเจนระงับหรือเปลี่ยนเส้นทางเป็นโดยอัตโนมัติส่งไปยังกระแสสำเร็จ ; เช่นWrite-Output "Honey, I'm $HOME"และ"Honey, I'm $HOME"เทียบเท่ากับหลังไม่เพียง แต่จะกระชับมากขึ้น แต่ยังเร็วกว่า
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.