2009-03-06 28 views
23

Đoạn mã sau cung cấp cho tôi một mảng các PSCustomObject, làm thế nào tôi có thể lấy nó để trả về một mảng các chuỗi?Làm cách nào để chọn Đối tượng Chọn trả về một loại thô (ví dụ: Chuỗi) thay vì PSCustomObject?

$files = Get-ChildItem $directory -Recurse | Select-Object FullName | Where-Object {!($_.psiscontainer)} 

(Như một câu hỏi thứ hai, phần psiscontainer cho là những gì tôi sao chép rằng từ một ví dụ trực tuyến?)

Post-Accept Edit: câu trả lời Hai lớn, ước gì có thể đánh dấu cả hai. Đã trao giải đáp ban đầu.

Trả lời

28

Bạn chỉ cần chọn thuộc tính bạn muốn từ các đối tượng. FullName trong trường hợp này.

$files = Get-ChildItem $directory -Recurse | Select-Object FullName | Where-Object {!($_.psiscontainer)} | foreach {$_.FullName} 

Chỉnh sửa: "? Nào foreach làm gì là những gì mà liệt kê trên" Giải thích cho Mark, người yêu cầu,

Lời giải thích của Sung Meister rất tốt, nhưng tôi sẽ thêm hướng dẫn tại đây vì nó có thể hữu ích.

Khái niệm chính là đường dẫn. Hình ảnh một loạt các quả bóng pingpong lăn xuống một cái ống hẹp sau cái kia. Đây là những đối tượng trong đường ống. Mỗi giai đoạn của đường ống - các đoạn mã được phân tách bằng ký tự ống (|) - có một đường ống đi vào nó và đường ống thoát ra khỏi nó. Đầu ra của một giai đoạn được kết nối với đầu vào của giai đoạn tiếp theo. Mỗi giai đoạn đưa các đối tượng khi chúng đến, làm mọi thứ với chúng, và gửi chúng trở lại vào đường ống đầu ra hoặc gửi ra các đối tượng mới, thay thế.

Get-ChildItem $directory -Recurse 

Get-ChildItem hướng dẫn từng tệp và thư mục gặp và đặt chúng vào đường ống.

Select-Object FullName 

Select-Object mất từng đối tượng FileSystemInfo như nó đến, lấy tài sản FullName từ nó (đó là một con đường trong trường hợp này), đặt tài sản đó thành một thương hiệu đối tượng tùy chỉnh mới nó đã tạo ra, và đặt mà tùy chỉnh đối tượng ra vào đường ống.

Where-Object {!($_.psiscontainer)} 

Đây là bộ lọc. Phải mất mỗi đối tượng, kiểm tra nó, và gửi nó trở lại hoặc loại bỏ nó tùy thuộc vào một số điều kiện. Mã của bạn ở đây có một lỗi, bằng cách này. Các đối tượng tùy chỉnh đến đây không có thuộc tính psiscontainer. Giai đoạn này không thực sự làm bất cứ điều gì. Mã của Sung Meister tốt hơn.

foreach {$_.FullName} 

Foreach, có tên dài là ForEach-Object, lấy mỗi đối tượng khi đến, và ở đây, lấy thuộc tính FullName, một chuỗi, từ đó. Bây giờ, đây là phần tinh tế: Bất kỳ giá trị nào không được tiêu thụ, nghĩa là, không bị bắt bởi một biến hoặc bị chặn theo một cách nào đó, được đưa vào đường dẫn đầu ra. Là một thử nghiệm, hãy thử thay thế giai đoạn đó bằng cách này:

foreach {'hello'; $_.FullName; 1; 2; 3} 

Thực sự dùng thử và kiểm tra đầu ra. Có bốn giá trị trong khối mã đó. Không ai trong số họ được tiêu thụ. Lưu ý rằng tất cả chúng đều xuất hiện trong đầu ra. Bây giờ hãy thử điều này:

foreach {'hello'; $_.FullName; $ x = 1; 2; 3} 

Lưu ý rằng một trong các giá trị đang được ghi lại bởi một biến. Nó không xuất hiện trong đường dẫn đầu ra.

+0

foreach làm gì? Cái gì đang liệt kê? –

+14

Một giải pháp tốt hơn là sử dụng select-object -expand FullName –

+0

FYI, bạn có thể gán cho một biến _and_ phát ra đầu ra bằng cách sử dụng 'tee-object'. Ví dụ: 'ls | select-first full -property fullname | % {$ _. FullName} | tee -variable firstpath' –

7

Đối với câu hỏi # 1

Tôi đã gỡ bỏ "chọn đối tượng" phần - đó là dư thừa và chuyển "ở đâu" bộ lọc trước khi "foreach" không giống như dangph's answer - Lọc càng sớm càng tốt để bạn đang đối phó với chỉ là một tập con của những gì bạn phải đối phó trong đường ống tiếp theo.

$files = Get-ChildItem $directory -Recurse | Where-Object {!$_.PsIsContainer} | foreach {$_.FullName} 

Đó đoạn mã cơ bản đọc

  • Nhận tất cả các file đường dẫn đầy đủ của tất cả các file một cách đệ quy (Get-ChildItem $ thư mục -recurse)
  • Lọc ra các thư mục (Nơi-Object {! $ _ .PsIsContainer})
  • Return ghi rõ họ tên tập tin duy nhất (foreach {$ _. FullName})
  • Lưu tất cả các tên file vào $ file

Lưu ý rằng đối foreach {$ _. FullName}, trong PowerShell, tuyên bố cuối cùng trong một khối kịch bản ({...}) được trả lại, trong trường hợp này $ _. FullName kiểu string

Nếu bạn thực sự cần phải có được một đối tượng thô, bạn không cần phải làm bất cứ điều gì sau khi thoát khỏi "chọn đối tượng". Nếu bạn sử dụng Select-Object nhưng muốn truy cập đối tượng thô, hãy sử dụng "PsBase", đó là một câu hỏi hoàn toàn khác (chủ đề) - Tham khảo "What's up with PSBASE, PSEXTENDED, PSADAPTED, and PSOBJECT?" để biết thêm thông tin về chủ đề đó

cho câu hỏi # 2

Và cũng lọc theo $ _ PsIsContainer nghĩa là bạn đang không bao gồm một đối tượng mức container -!. Trong trường hợp của bạn, bạn đang làm Get-ChildItem trên FileSystem cung cấp (bạn có thể thấy các nhà cung cấp PowerShell thông qua Get-PsProvider), vì vậy vùng chứa là DirectoryInfo (thư mục)

PsIsContainer có nghĩa là những thứ khác nhau trong các nhà cung cấp PowerShell khác nhau; ví dụ) Đối với Registry nhà cung cấp, PsIsContainer là loại Microsoft.Win32.RegistryKey Hãy thử điều này:

>pushd HKLM:\SOFTWARE 
>ls | gm 

[UPDATE] cho câu hỏi sau: nào foreach làm gì? Cái gì đang liệt kê? Để làm rõ, "foreach" là một bí danh cho "Foreach-Object" Bạn có thể tìm hiểu thông qua,

get-help foreach 

- hoặc -

get-alias foreach 

Bây giờ trong câu trả lời của tôi, "foreach "liệt kê từng cá thể đối tượng thuộc loại FileInfo được trả lại từ đường ống trước đó (có các thư mục được lọc). FileInfo có một thuộc tính được gọi là FullName và đó là những gì "foreach" đang liệt kê.
Và bạn tham chiếu đối tượng được truyền qua đường ống thông qua biến đường ống đặc biệt có tên "$ _" thuộc loại FileInfo trong ngữ cảnh khối tập lệnh "foreach".

+0

Việc giảng dạy làm gì? Cái gì đang liệt kê? –

+0

Hãy để tôi cập nhật câu trả lời – Sung

14

Để có được chuỗi cho tên tập tin, bạn có thể sử dụng

$files = Get-ChildItem $directory -Recurse | Where-Object {!($_.psiscontainer)} | Select-Object -ExpandProperty FullName 

Tham số -ExpandProperty cho phép bạn để lấy lại một đối tượng dựa vào loại tài sản quy định.

Kiểm tra thêm cho thấy rằng tính năng này không hoạt động với V1, nhưng chức năng đó được cố định với V2 CTP3.

3

Đối với V1, thêm bộ lọc sau để hồ sơ của bạn:

filter Get-PropertyValue([string]$name) { $_.$name } 

Sau đó, bạn có thể làm điều này:

gci . -r | ?{!$_.psiscontainer} | Get-PropertyName fullname 

BTW, nếu bạn đang sử dụng PowerShell Community Extensions bạn đã có này.

Về khả năng sử dụng Select-Object -Expand trong phiên bản V2, nó là một thủ thuật dễ thương nhưng không rõ ràng và thực sự không phải là những gì Select-Object cũng như -Expand có ý nghĩa. -Expand là tất cả về làm phẳng như SelectQany LINQ và Select-Object là về chiếu nhiều thuộc tính vào một đối tượng tùy chỉnh.

Các vấn đề liên quan