เหตุใด Powershell จึงแปลงอาร์เรย์สตริงด้วยหนึ่งรายการเป็นสตริงอย่างเงียบ ๆ


33

พิจารณาสคริปต์ Powershell ต่อไปนี้ซึ่งค้นหาโฟลเดอร์ใน C: \ ด้วย 'og' ในชื่อ:

PS C: \> (ls |% {$ _. ชื่อ} |? {$ _. ประกอบด้วย ("og")})
PerfLogs
ไฟล์โปรแกรม
Setup.log

ตอนนี้ฉัน จำกัด การค้นหาเพื่อรับรายการเดียว:

PS C: \> (ls |% {$ _. ชื่อ} |? {$ _. ประกอบด้วย ("Prog")})
ไฟล์โปรแกรม

สิ่งที่แปลกก็คือว่าการดำเนินการครั้งแรกที่อัตราผลตอบแทนถัวอาร์เรย์ในขณะที่การดำเนินงานที่สอง (ซึ่งเป็นความหมาย IMHO ดำเนินการเดียวกันดังนั้นจึงควรให้ผลผลิตชนิดเดียวกันผล) มีผลเป็นสตริง สามารถเห็นได้ในผลลัพธ์ต่อไปนี้:

PS C: \> (ls |% {$ _. ชื่อ} |? {$ _. ประกอบด้วย ("og")}) ความยาว
3
PS C: \> (ls |% {$ _. ชื่อ} |? {$ _. ประกอบด้วย ("Prog")}) ความยาว
13

สิ่งนี้อาจสร้างความรำคาญได้เนื่องจากเห็นว่ามีโฟลเดอร์ที่ตรงกับ 'og' น้อยกว่าเมื่อเทียบกับ 'Prog'

เห็นได้ชัดว่า PowerShell นัย 'unbox' อาร์เรย์รายการเดียวกับวัตถุเดียวและเราไม่เคยได้รับความยาว 1 อาร์เรย์ดูเหมือนว่าทุกครั้งที่ฉันต้องการที่จะนับผลลัพธ์ที่มาจากท่อฉันต้องตรวจสอบว่าฉัน ' จัดการกับอาเรย์หรือไม่

ฉันจะป้องกันไม่ให้สิ่งนี้เกิดขึ้นได้อย่างไร คุณจัดการกับสิ่งนี้ได้อย่างไร


เหล่านี้จาก StackOverflow อาจช่วยstackoverflow.com/questions/1827862/... stackoverflow.com/questions/1390782/...หากคุณไม่ได้ท่อไป$_.Containsแล้ว%{,,$_.Name}ทำงาน ...
บ๊อบ

คำตอบ:


56

เห็นได้ชัดว่า PowerShell บอกนัย 'unbox' อาเรย์รายการเดียวไปยังวัตถุเดียว

และ$nullผลรายการศูนย์ถึง

ฉันจะป้องกันไม่ให้สิ่งนี้เกิดขึ้นได้อย่างไร

คุณทำไม่ได้

คุณจัดการกับสิ่งนี้ได้อย่างไร

ใช้ตัวสร้างอาร์เรย์ ( @(...)) เพื่อบังคับคอลเลกชัน (อาจเป็นไปได้ที่มีค่าศูนย์หรือหนึ่งองค์ประกอบ) คืน:

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

ขอบคุณมันสมบูรณ์แบบ! ฉันจะโหวตทันทีที่ฉันมีชื่อเสียง 15 คน
ชีสดังนั้นหยุดทำร้ายโมนิก้า

2
ไม่แน่ใจว่าคุณสามารถ "บังคับ" ได้ @(1) | ConvertTo-Jsonยังคงส่งกลับแทน1 [1]
Marc

@Marc: ConvertTo-Jsonอย่าส่งคืนคอลเลกชัน: มันจะอ่านอินพุตทั้งหมดและแปลงเป็นสตริงเดี่ยว หากคุณต้องการให้วัตถุที่แปลงเป็นรายบุคคลคุณจะต้องดำเนินการแยกกัน
Richard

1
@ ริชาร์ดฉันคิดว่าคุณเข้าใจผิด: ฉันและคนอื่น ๆ โดยทั่วไปต้องการวัตถุทั้งหมด (เช่นชุดสะสม) ต่อเนื่อง (เช่นสำหรับการติดตาภายนอก) เราไม่สนใจการประมวลผลแต่ละวัตถุในการรวบรวมแยก ConvertTo-Json ควรคืนค่าสตริงซึ่งหากเรียกใช้ผ่าน ConvertFrom-Json จะส่งคืนออบเจ็กต์ดั้งเดิมแม้ว่าจะมีอาร์เรย์ / คอลเลกชันที่ว่างเปล่า
Marc

@Marc จุดของคำถามนี้คือการหลีกเลี่ยงการรักษาอาร์เรย์องค์ประกอบเดียวเป็นองค์ประกอบนั้น (ซึ่งเป็นปัญหาน้อยเนื่องจากการเปลี่ยนแปลง PSH ต่อไป: บันทึกวันที่ของคำถาม) คุณกำลังพูดถึงกรณีที่แตกต่างอย่างสิ้นเชิง (บังคับให้คอลเลกชันเป็นวัตถุเดียว) ดังนั้นฉันเข้าใจผิด
ริชาร์ด

2

สิ่งนี้ได้รับการแก้ไขใน PowerShell v3:

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

ในบันทึกย่อด้านข้างคุณจะพบว่าชื่อมีบางสิ่งบางอย่างที่ใช้ไวด์การ์ดหรือไม่:

PS> ls *og*

6
Shayฉันยังไม่สามารถให้ความเห็นเกี่ยวกับคำตอบได้ แต่ข้อความของคุณไม่เป็นความจริง PowerShell ยังคงองค์ประกอบกล่อง แต่พวกเขามีตามที่ระบุไว้ให้รายการเดียวค่า "นับ" อย่างไรก็ตามผลลัพธ์ของรายการเดียวยังคงไม่ถูกทำกล่อง คุณสามารถทดสอบตัวอย่างข้างต้นกับ PS 3 และดูผลลัพธ์
Tohuw

1
พฤติกรรมนี้ยังคงเหมือนเดิมใน PS 5
MEMark

ยังคงมีอยู่
James Wiseman

1
พฤติกรรมนี้ยังคงเหมือนเดิมใน PS 6.0.1
spuder

2

สังเกตความแตกต่างระหว่างผลลัพธ์ทั้งสองนี้:

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

ประเด็นก็คือการดำเนินการไปป์ไลน์ 'unboxing' ConvertTo-Json ยังคงเห็นวัตถุเป็นอาร์เรย์ถ้าเราใช้ InputObject แทนที่จะเป็น piping

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.