Tại sao Powershell âm thầm chuyển đổi một chuỗi chuỗi với một mục thành chuỗi


33

Hãy xem xét tập lệnh Powershell sau, tìm kiếm các thư mục trong C: \ với một 'og' trong tên của chúng:

PS C: \> (ls |% {$ _. Tên} |? {$ _. Chứa ("og")})
Nhật ký hoàn hảo
File chương trình
setup.log

Bây giờ tôi thu hẹp tìm kiếm để chỉ nhận một mục:

PS C: \> (ls |% {$ _. Tên} |? {$ _. Chứa ("Prog")})
File chương trình

Điều kỳ lạ là hoạt động đầu tiên mang lại một mảng , trong khi đó hoạt động thứ hai (là IMHO về mặt ngữ nghĩa giống như hoạt động, do đó, nó sẽ mang lại cùng loại kết quả) mang lại một chuỗi . Điều này có thể được nhìn thấy trong kết quả sau đây:

PS C: \> (ls |% {$ _. Tên} |? {$ _. Chứa ("og")}). Độ dài
3
PS C: \> (ls |% {$ _. Tên} |? {$ _. Chứa ("Prog")}). Độ dài
13

Điều này có thể rất khó chịu, vì rõ ràng có ít thư mục khớp với 'og' hơn so với những người khớp với 'Prog'.

Rõ ràng, PowerShell ngầm 'unboxes' một mảng một mục duy nhất cho một đối tượng và chúng tôi không bao giờ có được một mảng có độ dài 1. Dường như mỗi lần tôi muốn đếm kết quả qua đường ống, tôi phải kiểm tra xem tôi có ' m xử lý một mảng hay không.

Làm thế nào tôi có thể ngăn chặn điều này xảy ra? Làm thế nào để bạn đối phó với điều này?


Những thứ này từ StackOverflow có thể giúp: stackoverflow.com/questions/1827862/ Thẻ stackoverflow.com/questions/1390782/ trộm Nếu bạn không chuyển đến $_.Contains, thì hãy %{,,$_.Name}làm việc ...
Bob

Câu trả lời:


56

Rõ ràng, PowerShell ngầm 'unboxes' một mảng một mục cho một đối tượng,

không có kết quả mục nào $null.

Làm thế nào tôi có thể ngăn chặn điều này xảy ra?

Bạn không thể.

Làm thế nào để bạn đối phó với điều này?

Sử dụng hàm tạo mảng ( @(...)) để buộc một tập hợp (có thể có 0 hoặc một phần tử) trả về:

$res = @(ls | %{$_.Name} | ?{$_.Contains("Prog")})

Cảm ơn bạn, điều này là hoàn hảo! Tôi sẽ nâng cấp ngay khi tôi có 15 danh tiếng.
cheesus SO ngừng làm hại Monica

2
Không chắc chắn bạn có thể "buộc" nó. @(1) | ConvertTo-Jsonvẫn trả về 1thay [1].
Marc

@Marc: ConvertTo-Jsonkhông bao giờ trả về một bộ sưu tập: nó đọc toàn bộ đầu vào và chuyển đổi thành một chuỗi. Nếu bạn muốn các đối tượng đầu vào được chuyển đổi riêng lẻ, bạn cần xử lý riêng từng đối tượng.
Richard

1
@Richard, tôi nghĩ bạn hiểu nhầm: Tôi, và nhiều người khác, về cơ bản muốn toàn bộ đối tượng (tức là bộ sưu tập) được tuần tự hóa (ví dụ cho sự kiên trì bên ngoài). Chúng tôi không quan tâm đến việc xử lý riêng từng đối tượng trong bộ sưu tập. ConvertTo-Json sẽ trả về một chuỗi, nếu chạy qua, ConvertFrom-Json trả về đối tượng ban đầu mặc dù là một mảng / bộ sưu tập trống.
Marc

@Marc Điểm của câu hỏi này là để tránh việc xử lý một mảng phần tử duy nhất là phần tử đó (ít vấn đề hơn do những thay đổi PSH tiếp theo: lưu ý ngày của câu hỏi). Bạn đang nói về một trường hợp hoàn toàn khác (buộc một bộ sưu tập là một đối tượng duy nhất) do đó tôi hiểu lầm.
Richard

2

Điều này đã được giải quyết trong PowerShell v3:

http://bloss.microsoft.co.il/bloss/scriptfanatic/archive/2012/03/19/Counting-objects-in-PowerShell-3.0.aspx

Trên một ghi chú bên cạnh, bạn có thể tìm thấy nếu một tên có chứa một cái gì đó bằng cách sử dụng ký tự đại diện:

PS> ls *og*

6
Shay , tôi không thể bình luận về câu trả lời, nhưng tuyên bố của bạn là không đúng sự thật. PowerShell vẫn đóng hộp các phần tử, nhưng chúng có, như bạn đã lưu ý, đã cho các mục đơn lẻ một giá trị "Đếm". Kết quả mục duy nhất vẫn chưa được mở hộp, mặc dù. Bạn có thể kiểm tra ví dụ trên với PS 3 và xem kết quả.
Tohuw 17/07/13

1
Hành vi vẫn giống nhau trong PS 5.
MEMark

Đúng, def vẫn hiện diện
James Wiseman

1
Hành vi này vẫn giống như trong PS 6.0.1
spuder

2

Lưu ý sự khác biệt giữa hai kết quả này:

PS C:\> ConvertTo-Json -InputObject @(1)
[
    1
]
PS C:\> @(1)|ConvertTo-Json
1
PS C:\>

Vấn đề là 'unboxing' đang được thực hiện bởi hoạt động đường ống. ConvertTo-Json vẫn xem đối tượng là một mảng nếu chúng ta sử dụng InputObject thay vì đường ống.

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.