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?


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

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*

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.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.