Mengapa Powershell secara diam-diam mengubah array string dengan satu item ke string

33

Pertimbangkan skrip Powershell berikut ini, yang mencari folder di C: \ dengan 'og' di namanya:

PS C: \> (ls |% {$ _. Name} |? {$ _. Berisi ("og")})
PerfLogs
File program
setup.log

Sekarang saya mempersempit pencarian untuk mendapatkan hanya satu item:

PS C: \> (ls |% {$ _. Name} |? {$ _. Berisi ("Prog")})
File program

Yang aneh adalah bahwa operasi pertama menghasilkan array , sedangkan operasi kedua (yang IMHO operasi semantik yang sama, sehingga harus menghasilkan jenis hasil yang sama) menghasilkan string . Ini bisa dilihat pada hasil berikut:

PS C: \> (ls |% {$ _. Name} |? {$ _. Berisi ("og")}). Panjang
3
PS C: \> (ls |% {$ _. Name} |? {$ _. Berisi ("Prog")}). Panjang
13

Ini bisa sangat menjengkelkan, karena ternyata ada lebih sedikit folder yang cocok dengan 'og' daripada mereka yang cocok dengan 'Prog'.

Jelas, PowerShell secara implisit 'unboxes' satu-item array ke satu objek, dan kami tidak pernah mendapatkan array dengan panjang 1. Tampaknya setiap kali saya ingin menghitung hasil yang datang melalui pipa, saya harus memeriksa apakah saya ' Saya berurusan dengan array atau tidak.

Bagaimana saya bisa mencegah hal ini terjadi? Bagaimana Anda menangani ini?

cheesus, jadi berhentilah merugikan Monica
sumber
Ini dari StackOverflow dapat membantu: stackoverflow.com/questions/1827862/... stackoverflow.com/questions/1390782/... Jika Anda tidak melakukan piping $_.Contains, maka %{,,$_.Name}berfungsi ...
Bob

Jawaban:

56

Jelas, PowerShell secara implisit 'unboxes' satu-item array ke objek tunggal,

Dan hasil nol item untuk $null.

Bagaimana saya bisa mencegah hal ini terjadi?

Kamu tidak bisa

Bagaimana Anda menangani ini?

Gunakan konstruktor array ( @(...)) untuk memaksa koleksi (mungkin dengan nol atau satu elemen) kembali:

$res = @(ls | %{$_.Name} | ?{$_.Contains("Prog")})
Richard
sumber
Terima kasih, ini sempurna! Saya akan angkat suara segera setelah saya memiliki 15 reputasi.
cheesus SANGAT berhenti melukai Monica
2
Tidak yakin Anda bisa "memaksanya". @(1) | ConvertTo-Jsonmasih kembali 1sebagai gantinya [1].
Marc
@ Markc: ConvertTo-Jsontidak pernah mengembalikan koleksi: itu membaca seluruh input dan mengkonversi ke string tunggal. Jika Anda ingin objek input dikonversi secara individual, Anda harus memprosesnya secara terpisah.
Richard
1
@ Richard, saya pikir Anda salah paham: Saya, dan banyak lainnya, pada dasarnya ingin seluruh objek (yaitu koleksi) serial (misalnya untuk ketekunan eksternal). Kami tidak tertarik memproses setiap objek dalam koleksi secara terpisah. ConvertTo-Json harus mengembalikan string yang, jika dijalankan melalui, ConvertFrom-Json mengembalikan objek asli meskipun array / koleksi kosong.
Marc
@ Mark Maksud dari pertanyaan ini adalah untuk menghindari perlakuan dari array elemen tunggal sebagai elemen itu (yang kurang dari masalah karena perubahan PSH berikutnya: perhatikan tanggal pertanyaan). Anda berbicara tentang kasus yang sama sekali berbeda (memaksa koleksi menjadi objek tunggal) maka saya salah paham.
Richard
2

Ini telah diatasi dalam PowerShell v3:

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

Di samping catatan, Anda dapat menemukan jika nama berisi sesuatu menggunakan wildcard:

PS> ls *og*
Shay Levy
sumber
6
Shay , saya belum bisa mengomentari jawaban, tetapi pernyataan Anda tidak benar. PowerShell masih mengotak-kotakkan elemen, tetapi mereka, seperti yang Anda catat, memberi satu item nilai "Hitung". Hasil satu item masih belum dikotak. Anda dapat menguji contoh di atas terhadap PS 3 dan melihat hasilnya.
Tohuw
1
Perilaku ini masih sama di PS 5.
MEMark
Yap, def masih ada
James Wiseman
1
Perilaku ini masih sama di PS 6.0.1
spuder
2

Perhatikan perbedaan antara dua hasil ini:

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

Intinya adalah bahwa 'unboxing' sedang dilakukan oleh operasi pipa. ConvertTo-Json masih melihat objek sebagai array jika kita menggunakan InputObject daripada perpipaan.

Larry Young
sumber