Cara mengeluarkan sesuatu di PowerShell

211

Saya menjalankan skrip PowerShell dari dalam file batch. Script mengambil halaman web dan memeriksa apakah konten halaman adalah string "OK".

Skrip PowerShell mengembalikan tingkat kesalahan ke skrip batch.

Script batch dijalankan oleh ScriptFTP , sebuah program otomatisasi FTP. Jika terjadi kesalahan, saya dapat meminta ScriptFTP mengirim output konsol penuh ke administrator melalui E-Mail.

Dalam skrip PowerShell, saya ingin menampilkan nilai kembali dari situs web jika bukan "OK", sehingga pesan kesalahan akan dimasukkan dalam output konsol, dan dengan demikian dalam surat status.

Saya baru mengenal PowerShell dan tidak yakin fungsi keluaran mana yang digunakan untuk ini. Saya dapat melihat tiga:

  • Tuan Rumah Penulis
  • Tulis-Output
  • Tulis-Kesalahan

Apa hal yang benar untuk digunakan untuk menulis ke Windows yang setara stdout?

Pekka
sumber

Jawaban:

197

Cukup mengeluarkan sesuatu adalah PowerShell adalah sesuatu yang indah - dan salah satu kekuatan terbesarnya. Misalnya, Hello, World! aplikasi dikurangi menjadi satu baris:

"Hello, World!"

Ini menciptakan objek string, memberikan nilai yang disebutkan di atas, dan menjadi item terakhir pada pipeline perintah yang memanggil .toString()metode dan output hasilnya STDOUT(secara default). Suatu keindahan.

Write-*Perintah lain khusus untuk mengeluarkan teks ke aliran terkait, dan menempatkannya sebagai tempat.

Goyuix
sumber
9
Bukan itu yang sebenarnya terjadi. Ini adalah ekspresi literal string dan satu-satunya hal dalam pipanya. Jadi itu setara dengan "Hello, World!" | Out-Host. Out-Hostdi sisi lain mengirim objek ke host PowerShell untuk tampilan dan implementasinya tergantung pada host. Host konsol mengirimkannya ke pegangan keluaran standar (melewati Out-Defaultsepanjang jalan), memang. PowerShell ISE menampilkannya di panel output, namun, dan host lain mungkin melakukan hal lain sama sekali.
Joey
5
Objek juga tidak dikonversi secara acak ke string, tetapi melewati formatter yang memutuskan apa yang harus dilakukan dengan mereka. Itu sebabnya Anda melihat Get-ChildItemoutput datang dalam bentuk tabel, misalnya, dan hasilnya dengan banyak properti (misalnya WMI) Format-Listsebagai gantinya.
Joey
120

Saya pikir dalam hal ini Anda akan membutuhkan Write-Output .

Jika Anda memiliki skrip seperti

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

kemudian, jika Anda memanggil skrip dengan output redirected, sesuatu seperti yourscript.ps1 > out.txt, Anda akan mendapatkan test2di layar test1\ntest3\ndi "out.txt".

Perhatikan bahwa "test3" dan baris Write-Output akan selalu menambahkan baris baru ke teks Anda dan tidak ada cara di PowerShell untuk menghentikan ini (artinya, echo -ntidak mungkin di PowerShell dengan perintah asli). Jika Anda ingin ( Bash ) fungsionalitas yang agak dasar dan mudahecho -n kemudian lihat jawaban samthebest .

Jika file batch menjalankan perintah PowerShell, kemungkinan besar akan menangkap perintah Write-Output. Saya telah melakukan "diskusi panjang" dengan administrator sistem tentang apa yang harus ditulis ke konsol dan apa yang tidak. Kami sekarang telah sepakat bahwa satu-satunya informasi jika skrip dieksekusi berhasil atau mati harus di Write-Host-red, dan segala sesuatu yang penulis skrip mungkin perlu ketahui tentang eksekusi (item apa yang diperbarui, bidang apa yang ditetapkan, dan lain-lain) berjalan untuk Menulis-Output. Dengan cara ini, ketika Anda mengirimkan skrip ke administrator sistem, ia dapat dengan mudah runthescript.ps1 >someredirectedoutput.txtdan melihat di layar, jika semuanya OK. Lalu kirim "someredirectedoutput.txt" kembali ke pengembang.

kenaifan
sumber
9

Saya pikir berikut ini adalah pameran Echo vs Write-Host yang bagus . Perhatikan bagaimana test () benar-benar mengembalikan array int, bukan int tunggal karena seseorang dapat dengan mudah dituntun untuk percaya.

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])"

Output terminal di atas:

123
x of type 'Object[]' = 456 789
$x[0] = 456
$x[1] = 789
pengguna2426679
sumber
Saya bisa melihat ini sepanjang hari ... Tapi mengapa $x = testhanya mencetak 123dan tidak juga 456?
not2qubit
7

Anda dapat menggunakan semua ini dalam skenario Anda karena mereka menulis ke aliran default (output dan kesalahan). Jika Anda mem-piping output ke commandlet lain Anda ingin menggunakan Write-Output , yang pada akhirnya akan berakhir di Write-Host .

Artikel ini menjelaskan berbagai opsi keluaran: PowerShell O untuk Output

GrayWizardx
sumber
1
Terima kasih untuk tautannya. Astaga, ini rumit . Jika Write-host adalah semacam fungsi endpoint atau flushing, saya akan mencoba dan menggunakannya dan melaporkan kembali.
Pekka
3
Write-Host "Found file - " + $File.FullName -ForegroundColor Magenta

Magenta dapat menjadi salah satu dari nilai enumerator "System.ConsoleColor" - Hitam, DarkBlue, DarkGyan, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Abu-abu, DarkGray, Biru, Hijau, Cyan, Merah, Magenta, Kuning, Putih.

Ini + $File.FullNameopsional, dan menunjukkan cara memasukkan variabel ke dalam string.

Yordania
sumber
2

Anda tidak bisa mendapatkan PowerShell untuk mengabaikan baris baru yang sial itu. Tidak ada skrip atau cmdlet yang melakukan ini.

Tentu saja Write-Host benar-benar omong kosong karena Anda tidak dapat mengalihkan / menyalurkannya! Anda hanya perlu menulis sendiri:

using System;

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

Misalnya

PS C:\> writetostdout finally I can write to stdout like echo -n
finally I can write to stdout like echo -nPS C:\>
samthebest
sumber
Anda bisa melakukan ini di PowerShell sendiri. [System.Console] :: Write ("stringy") Namun Anda tidak akan dapat mengalihkannya sama sekali di PowerShell.
Nicholi
1
Tentu kamu bisa. Lihat pertanyaan ini
Slogmeister Extraordinaire
1

Apa yang akan menjadi hal yang tepat untuk digunakan untuk menulis ke Windows setara dengan stdout?

Dalam efek , tapi sangat sayangnya , baik Windows PowerShell dan PowerShell Core dari v7.0, mengirim semua dari mereka 6 (!) Keluaran aliran ke stdout ketika dipanggil dari luar , melalui PowerShell ini CLI .

  • Lihat masalah GitHub ini untuk diskusi tentang perilaku bermasalah ini, yang kemungkinan tidak akan diperbaiki demi kompatibilitas ke belakang.

  • Dalam praktiknya, ini berarti bahwa aliran PowerShell apa pun yang Anda kirim akan dilihat sebagai keluaran stdout oleh penelepon eksternal:

    • Misalnya, jika Anda menjalankan berikut dari cmd.exe, Anda akan melihat ada output, karena stdout pengalihan untuk NULberlaku sama untuk semua PowerShell stream:

      • C:\>powershell -noprofile -command "Write-Error error!" >NUL
    • Namun - anehnya - jika Anda mengarahkan stderr , PowerShell tidak mengirim aliran kesalahan untuk stderr , sehingga dengan 2>Anda dapat menangkap output kesalahan-aliran selektif; output berikut hanya 'hi'- output stream-berhasil - sambil menangkap output stream-kesalahan dalam file err.txt:

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

The diinginkan perilaku adalah:

  • Kirim aliran keluaran sukses (nomor 1) PowerShell ke stdout .
  • Kirim output dari semua stream lain ke stderr , yang merupakan satu-satunya pilihan, mengingat bahwa antara proses hanya ada 2 stream output yang ada - stdout (output standar) untuk data , dan stderr (standard error) untuk pesan kesalahan dan semua jenis pesan lainnya - seperti sebagai informasi status - itu bukan data .

  • Dianjurkan untuk membuat perbedaan ini dalam kode Anda, meskipun saat ini tidak dihormati .


Di dalam PowerShell :

  • Write-Hostadalah untuk tampilan output , dan mem - bypass aliran output yang sukses - dengan demikian, outputnya tidak dapat (secara langsung) ditangkap dalam suatu variabel atau ditekan atau dialihkan.

    • Maksud aslinya adalah hanya untuk membuat umpan balik pengguna dan membuat antarmuka pengguna yang sederhana dan berbasis konsol (keluaran berwarna).

    • Karena ketidakmampuan sebelum ditangkap atau diarahkan, PowerShell versi 5 yang dibuat Write-Hostuntuk yang baru diperkenalkan aliran informasi (nomor 6), sehingga sejak itu adalah mungkin untuk menangkap dan redirect Write-Hostoutput.

  • Write-Errordimaksudkan untuk menulis kesalahan yang tidak berakhir ke aliran kesalahan (angka 2); secara konseptual, aliran kesalahan adalah setara dengan stderr.

  • Write-Outputmenulis untuk aliran [keluaran] sukses (angka 1), yang secara konseptual setara dengan stdout; itu adalah aliran untuk menulis data (hasil) ke.

    • Namun, penggunaan eksplisit Write-Outputjarang diperlukan karena fitur output implisit PowerShell :
      • Output dari perintah atau ekspresi apa pun yang tidak secara eksplisit ditangkap, ditekan atau dialihkan secara otomatis dikirim ke aliran keberhasilan ; misalnya, Write-Output "Honey, I'm $HOME"dan "Honey, I'm $HOME"setara, dengan yang terakhir tidak hanya lebih ringkas, tetapi juga lebih cepat.
mklement0
sumber