2009-03-06 13 views
23

El siguiente código me proporciona una matriz de PSCustomObjects, ¿cómo puedo obtener que devuelva una matriz de cadenas?¿Cómo hacer que Select-Object devuelva un tipo sin formato (por ejemplo, String) en lugar de PSCustomObject?

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

(Como una cuestión secundaria, lo que es la parte PSIsContainer para copié que a partir de un ejemplo en línea?)

Edit Post-Accept: Dos grandes respuestas, desearía poder marcar los dos. Haber otorgado la respuesta original.

Respuesta

28

Solo necesita elegir la propiedad que desea de los objetos. FullName en este caso.

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

Editar: "¿? ¿Qué hace el foreach Lo que es que la enumeración sobre" Explicación para Mark, que pide,

La explicación de Sung Meister es muy buena, pero agregaré un tutorial aquí porque podría ser útil.

El concepto clave es la tubería. Imagina una serie de bolas de ping-pong rodando por un tubo estrecho una después de la otra. Estos son los objetos en la tubería. Cada etapa de la tubería - los segmentos de código separados por caracteres de tubería (|) - tiene una tubería que entra y sale de la tubería. La salida de una etapa está conectada a la entrada de la siguiente etapa. Cada etapa toma los objetos a medida que llegan, les hace cosas y los envía de regreso a la tubería de salida o envía nuevos objetos de reemplazo.

Get-ChildItem $directory -Recurse 

Get-ChildItem paseos por el sistema de archivos de la creación de objetos FileSystemInfo que representan a cada archivo y directorio que encuentra y los pone en la tubería.

Select-Object FullName 

Select-Object toma cada objeto FileSystemInfo a medida que llega, agarra la propiedad FullName de ella (que es un camino en este caso), pone esa propiedad en un nuevo objeto personalizado de marca que ha creado, y pone esa objeto personalizado en la tubería.

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

Esto es un filtro. Toma cada objeto, lo examina y lo envía de vuelta o lo descarta dependiendo de alguna condición. Su código aquí tiene un error, por cierto. Los objetos personalizados que llegan aquí no tienen una propiedad psiscontainer. Esta etapa en realidad no hace nada. El código de Sung Meister es mejor.

foreach {$_.FullName} 

Foreach, cuyo nombre largo es ForEach-Object, agarra cada objeto a medida que llega, y aquí, agarra la propiedad FullName, una cadena, de ella. Ahora, aquí está la parte sutil: cualquier valor que no se consuma, es decir, no sea capturado por una variable o suprimido de alguna manera, se ponga en la línea de salida. Como un experimento, intente reemplazar esa etapa con esto:

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

En realidad probarlo y examine la salida. Hay cuatro valores en ese bloque de código. Ninguno de ellos se consume. Tenga en cuenta que todos aparecen en la salida. Ahora intente esto:

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

Observe que uno de los valores está siendo capturado por una variable. No aparece en la canalización de salida.

+0

¿Qué hace el foreach? ¿Qué es eso que enumera? –

+14

Una mejor solución es usar select-object -expand FullName –

+0

FYI, puede asignar a una variable _and_ emitir a la salida utilizando 'tee-object'. Ejemplo: 'ls | seleccione -primero 1-nombre completo de propiedad | % {$ _. FullName} | tee -variable firstpath' –

7

la pregunta N ° 1

me han quitado "select-objeto" parte - es redundante y movido "donde" filtro antes "foreach" a diferencia de dangph's answer - filtro tan pronto como sea posible a fin de que se trata de solo un subconjunto de lo que tiene que tratar en la próxima línea de tubería.

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

Ese fragmento de código lee esencialmente

  • obtener todos los archivos de la ruta completa de todos los archivos de forma recursiva (Get-ChildItem $ directorio -Recurse)
  • Filtro cabo directorios (Where-Object {! $ _ .PsIsContainer})
  • Volver nombre de archivo completo solamente (foreach {$ _. NombreCompleto})
  • Guardar todos los nombres de los archivos en los archivos de $

Tenga en cuenta que para foreach {$ _. NombreCompleto}, en PowerShell, última instrucción en un bloque de script ({...}) se devuelve, en este caso $ _. NombreCompleto de tipo cadena

Si realmente necesita obtener un objeto en bruto, no necesita hacer nada después de deshacerse de "objeto de selección". Si tuviera que usar Select-Object pero desea acceder al objeto sin procesar, use "PsBase", que es una pregunta totalmente diferente (tema) - Consulte "What's up with PSBASE, PSEXTENDED, PSADAPTED, and PSOBJECT?" para obtener más información sobre ese tema

Para la pregunta n.º 2

Y también filtrado por $ _ PSIsContainer significa que usted está excluyendo un contenedor objetos de nivel -. en su caso, se están haciendo Get-ChildItem en un proveedor de sistema de archivos (se puede ver proveedores de PowerShell a través de Get-PsProvider), por lo que el contenedor es DirectoryInfo (carpeta)

PsIsContainer significa diferentes cosas en diferentes proveedores de PowerShell; por ejemplo) Para proveedor del Registro, PSIsContainer es de tipo Microsoft.Win32.RegistryKey Prueba esto:

>pushd HKLM:\SOFTWARE 
>ls | gm 

[ACTUALIZACIÓN] al siguiente pregunta: ¿Qué hace el foreach? ¿Qué es eso que enumera? Para aclarar, "foreach" es un alias de "Foreach-Object" Usted puede averiguar a través,

get-help foreach 

- o -

get-alias foreach 

Ahora en mi respuesta, "foreach "está enumerando cada instancia de objeto de tipo FileInfo devuelta desde la tubería anterior (que tiene directorios filtrados). FileInfo tiene una propiedad llamada FullName y eso es sobre lo que "foreach" está enumerando.
Y usted hace referencia al objeto pasado a través de una tubería a través de una variable especial llamada "$ _" que es del tipo FileInfo dentro del contexto del bloque de script de "foreach".

+0

¿Qué hace el foreach? ¿Qué es eso que enumera? –

+0

Déjame actualizar la respuesta – Sung

14

Para obtener la cadena para el nombre del archivo que se puede utilizar

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

El parámetro -ExpandProperty le permite volver un objeto en función del tipo de la propiedad especificada.

Pruebas adicionales muestran que esto no funcionó con V1, pero que la funcionalidad se corrigió a partir del V2 CTP3.

3

para V1, añadir el siguiente filtro para su perfil:

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

entonces usted puede hacer esto:

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

Por cierto, si está utilizando el PowerShell Community Extensions que ya tienen esto.

En cuanto a la capacidad de usar Select-Object -Expand en V2, es un truco lindo pero no obvio y realmente no es para lo que Select-Object ni -Expand fue diseñado. -Expand se trata de aplanar como LINK SelectMany y Select-Object se trata de la proyección de múltiples propiedades en un objeto personalizado.

Cuestiones relacionadas