Cách xuất nội dung nào đó trong PowerShell


210

Tôi đang chạy tập lệnh PowerShell từ trong một tệp bó. Tập lệnh tìm nạp một trang web và kiểm tra xem nội dung của trang có phải là chuỗi "OK" hay không.

Tập lệnh PowerShell trả về mức lỗi cho tập lệnh bó.

Tập lệnh bó được thực thi bởi ScriptFTP , một chương trình tự động hóa FTP. Nếu xảy ra lỗi, tôi có thể yêu cầu ScriptFTP gửi đầu ra giao diện điều khiển đầy đủ cho quản trị viên thông qua E-Mail.

Trong tập lệnh PowerShell, tôi muốn xuất giá trị trả về từ trang web nếu nó không "OK", vì vậy thông báo lỗi được đưa vào đầu ra của giao diện điều khiển và do đó trong thư trạng thái.

Tôi chưa quen với PowerShell và không chắc nên sử dụng chức năng đầu ra nào cho việc này. Tôi có thể thấy ba:

  • Máy chủ lưu trữ
  • Đầu ra ghi
  • Viết sai

Điều gì sẽ là điều đúng đắn để sử dụng để ghi vào Windows tương đương stdout?

Câu trả lời:


196

Đơn giản chỉ cần xuất ra một cái gì đó là PowerShell là một thứ đẹp đẽ - và là một thế mạnh lớn nhất của nó. Ví dụ, Hello, World! ứng dụng được giảm xuống một dòng duy nhất:

"Hello, World!"

Nó tạo ra một đối tượng chuỗi, gán giá trị nói trên và là mục cuối cùng trên đường ống lệnh mà nó gọi .toString()phương thức và đưa kết quả ra STDOUT(theo mặc định). Một điều của vẻ đẹp.

Các Write-*lệnh khác là cụ thể để xuất văn bản cho các luồng liên kết của chúng và có vị trí của chúng như vậy.


9
Đó không thực sự là những gì xảy ra. Đó là một biểu thức chuỗi theo nghĩa đen và là điều duy nhất trong đường ống của nó. Do đó, nó tương đương với "Hello, World!" | Out-Host. Out-Hostmặt khác gửi các đối tượng đến máy chủ PowerShell để hiển thị và việc thực hiện nó phụ thuộc vào máy chủ. Máy chủ bàn điều khiển gửi chúng đến tay cầm đầu ra tiêu chuẩn (đi Out-Defaultdọc đường), thực sự. Tuy nhiên, PowerShell ISE hiển thị chúng trong khung đầu ra của nó và các máy chủ khác có thể hoàn toàn làm những việc khác.
Joey

5
Các đối tượng cũng không được chuyển đổi một cách mù quáng thành chuỗi, nhưng chuyển qua một bộ định dạng quyết định việc phải làm với chúng. Đó là lý do tại sao bạn thấy Get-ChildItemđầu ra đến ở dạng bảng, ví dụ, và kết quả có nhiều thuộc tính (ví dụ WMI) mặc định Format-Listthay thế.
Joey

120

Tôi nghĩ trong trường hợp này bạn sẽ cần Write-Output .

Nếu bạn có một kịch bản như

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

sau đó, nếu bạn gọi tập lệnh với đầu ra được chuyển hướng, đại loại như yourscript.ps1 > out.txt, bạn sẽ nhận được test2trên màn hình test1\ntest3\ntrong "out.txt".

Lưu ý rằng "test3" và dòng Viết ra sẽ luôn nối một dòng mới vào văn bản của bạn và PowerShell không có cách nào để ngăn chặn điều này (điều đó echo -nlà không thể trong PowerShell với các lệnh gốc). Nếu bạn muốn (chức năng hơi cơ bản và dễ dàng trong Bash ) echo -nthì hãy xem câu trả lời của samthebest .

Nếu một tệp bó chạy lệnh PowerShell, rất có thể nó sẽ nắm bắt lệnh Write-Output. Tôi đã có "cuộc thảo luận dài" với các quản trị viên hệ thống về những gì nên viết cho bảng điều khiển và những gì không nên viết. Bây giờ chúng tôi đã đồng ý rằng thông tin duy nhất nếu tập lệnh được thực thi thành công hoặc đã chết phải được chỉnh sửa Write-Hostvà mọi thứ mà tác giả của tập lệnh có thể cần biết về việc thực thi (mục nào được cập nhật, trường nào được đặt, et cetera) đi để ghi đầu ra. Bằng cách này, khi bạn gửi một tập lệnh cho quản trị viên hệ thống, anh ta có thể dễ dàng runthescript.ps1 >someredirectedoutput.txtvà nhìn thấy trên màn hình, nếu mọi thứ đều ổn. Sau đó gửi lại "someredirectedoutput.txt" cho các nhà phát triển.


9

Tôi nghĩ sau đây là một triển lãm tốt về Echo so với Write-Host . Lưu ý cách test () thực sự trả về một mảng int, không phải là một int như người ta có thể dễ dàng dẫn đến tin tưởng.

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

Đầu ra của thiết bị đầu cuối ở trên:

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

Tôi có thể nhìn vào điều này cả ngày ... Nhưng tại sao $x = testchỉ in 123và không in 456?
not2qubit

7

Bạn có thể sử dụng bất kỳ thứ nào trong kịch bản này vì chúng ghi vào luồng mặc định (đầu ra và lỗi). Nếu bạn đang chuyển đầu ra sang một lệnh khác, bạn sẽ muốn sử dụng Đầu ra ghi , cuối cùng sẽ kết thúc trong Máy chủ ghi .

Bài viết này mô tả các tùy chọn đầu ra khác nhau: PowerShell O dành cho Đầu ra


1
Cảm ơn các liên kết. Trời ơi, chuyện này phức tạp quá . Nếu Write-host là một loại chức năng điểm cuối hoặc chức năng xóa, tôi sẽ thử và đi với điều đó và báo cáo lại.
Pekka

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

Magenta có thể là một trong những giá trị liệt kê "System.ConsoleColor" - Đen, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Grey, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White.

Đây + $File.FullNamelà tùy chọn và hiển thị cách đặt một biến vào chuỗi.


2

Bạn chỉ đơn giản là không thể có được PowerShell để giới thiệu những dòng mới phiền phức đó. Không có tập lệnh hoặc lệnh ghép ngắn nào thực hiện điều này.

Tất nhiên Write-Host hoàn toàn vô nghĩa vì bạn không thể chuyển hướng / đường ống từ nó! Bạn chỉ cần viết riêng của bạn:

using System;

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

Ví dụ

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

Bạn có thể làm điều này trong powershell chính nó. [System.Console] :: Write ("chuỗi") Tuy nhiên, bạn sẽ không thể chuyển hướng nó ở tất cả trong powershell.
Nicholi

1
Chắc chắn bạn có thể. Xem câu hỏi này
Slogmeister Extraordinaire

1

Điều gì sẽ là điều đúng đắn để sử dụng để ghi vào Windows tương đương với thiết bị xuất chuẩn?

Thực tế , nhưng rất tiếc , cả Windows PowerShell và PowerShell Core kể từ v7.0, đều gửi tất cả 6 luồng đầu ra (!) Của chúng đến thiết bị xuất chuẩn khi được gọi từ bên ngoài , thông qua CLI của PowerShell .

  • Xem vấn đề GitHub này để thảo luận về hành vi có vấn đề này, có khả năng sẽ không được khắc phục vì mục đích tương thích ngược.

  • Trong thực tế, điều này có nghĩa là bất kỳ luồng PowerShell nào bạn gửi đầu ra sẽ được xem là đầu ra xuất chuẩn của một người gọi bên ngoài:

    • Ví dụ: nếu bạn chạy các mục sau cmd.exe, bạn sẽ không thấy đầu ra, vì chuyển hướng xuất chuẩn sẽ NULáp dụng như nhau cho tất cả các luồng PowerShell:

      • C:\>powershell -noprofile -command "Write-Error error!" >NUL
    • Tuy nhiên - thật kỳ lạ - nếu bạn chuyển hướng stderr , PowerShell sẽ gửi luồng lỗi của nó đến stderr , để 2>bạn có thể nắm bắt đầu ra luồng lỗi một cách chọn lọc; các đầu ra sau đây chỉ 'hi'- đầu ra luồng thành công - trong khi chụp đầu ra luồng lỗi trong tệp err.txt:

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

Các mong muốn hành vi là:

  • Gửi luồng đầu ra thành công1 của PowerShell (số ) đến thiết bị xuất chuẩn .
  • Gửi đầu ra từ tất cả các luồng khác đến stderr , là tùy chọn duy nhất, cho rằng giữa các quy trình chỉ tồn tại 2 luồng đầu ra - stdout (đầu ra tiêu chuẩn) cho dữ liệu và stderr (lỗi tiêu chuẩn) cho các thông báo lỗi tất cả các loại thông báo khác - chẳng hạn như thông tin trạng thái - đó không phải là dữ liệu .

  • Bạn nên tạo sự khác biệt này trong mã của mình, mặc dù hiện tại nó không được tôn trọng .


Bên trong PowerShell :

  • Write-Hostcho đầu ra hiển thịbỏ qua luồng đầu ra thành công - như vậy, đầu ra của nó không thể (trực tiếp) được ghi lại trong một biến cũng không bị triệt tiêu cũng không được chuyển hướng.

    • Mục đích ban đầu của nó chỉ đơn giản là tạo phản hồi của người dùng và tạo giao diện người dùng đơn giản, dựa trên bảng điều khiển (đầu ra màu).

    • Do không có khả năng trước khi bị bắt giữ hoặc chuyển hướng, PowerShell phiên bản 5 làm Write-Hostđể vừa được giới thiệu dòng thông tin (số 6), vì vậy kể từ đó nó có thể thu hồi và chuyển hướng Write-Hostđầu ra.

  • Write-Errorcó nghĩa là để viết các lỗi không kết thúc vào luồng lỗi (số 2); về mặt khái niệm, luồng lỗi tương đương với stderr.

  • Write-Outputghi vào luồng [đầu ra] thành công (số 1), tương đương về mặt khái niệm với thiết bị xuất chuẩn; đó là luồng để ghi dữ liệu (kết quả) vào.

    • Tuy nhiên, việc sử dụng rõ ràng Write-Outputhiếm khi cần thiết do tính năng đầu ra ngầm của PowerShell :
      • Đầu ra từ bất kỳ lệnh hoặc biểu thức nào không được nắm bắt, triệt tiêu hoặc chuyển hướng rõ ràng sẽ tự động được gửi đến luồng thành công ; ví dụ, Write-Output "Honey, I'm $HOME""Honey, I'm $HOME"tương đương, với cái sau không chỉ ngắn gọn hơn mà còn nhanh hơn.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.