2009-03-06 13 views
23

Il seguente codice mi fornisce un array di oggetti PSCustom, come posso ottenere un array di stringhe?Come ottenere Select-Object per restituire un tipo non elaborato (ad esempio String) anziché PSCustomObject?

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

(come una questione secondaria, che cosa è la parte psiscontainer per ho copiato che da un esempio in linea?)

Post-Accept Edit: Due grandi risposte, vorrei poter segnare entrambi. Hai assegnato la risposta originale.

risposta

28

Hai solo bisogno di scegliere la proprietà che vuoi dagli oggetti. FullName in questo caso.

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

Edit: "? Cosa fa il foreach fare ciò che è che l'enumerazione finita" Spiegazione per Mark, che chiede,

La spiegazione di Sung Meister è molto buona, ma aggiungerò una spiegazione qui perché potrebbe essere utile.

Il concetto chiave è la pipeline. Immaginate una serie di palle da ping-pong che rotolano lungo uno stretto tubo uno dopo l'altro. Questi sono gli oggetti nella pipeline. Ogni fase della pipeline - i segmenti di codice separati dai caratteri di pipe (|) - ha una pipa che entra e la pipa ne esce. L'uscita di uno stadio è collegata all'ingresso dello stadio successivo. Ogni fase prende gli oggetti mentre arrivano, fa loro delle cose e li rimanda nella pipeline di uscita o invia nuovi oggetti sostitutivi.

Get-ChildItem $directory -Recurse 

Get-ChildItem passeggiate attraverso il filesystem creare oggetti FileSystemInfo che rappresentano ogni file e directory che incontra, e li mette nella pipeline.

Select-Object FullName 

Select-Object prende ogni oggetto FileSystemInfo come arriva, afferra la proprietà FullName da esso (che è un percorso in questo caso), mette che la proprietà in un nuovo oggetto personalizzato che ha creato, e mette che oggetto personalizzato fuori nella conduttura.

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

Questo è un filtro. Prende ogni oggetto, lo esamina e lo rimanda o lo scarta a seconda di alcune condizioni. A proposito, il tuo codice ha un bug. Gli oggetti personalizzati che arrivano qui non hanno una proprietà di psiscontainer. Questo stadio in realtà non fa nulla. Il codice di Sung Meister è migliore.

foreach {$_.FullName} 

Foreach, il cui nome lungo è ForEach-Object, afferra ciascun oggetto come arriva, e qui, afferra la proprietà FullName, una stringa, da esso. Ora, ecco la parte sottile: qualsiasi valore che non viene consumato, cioè non viene catturato da una variabile o soppresso in qualche modo, viene inserito nella pipeline di output. Come esperimento, provare a sostituire quella fase con questo:

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

realtà provare e esaminare l'output. Ci sono quattro valori in quel blocco di codice. Nessuno di loro è consumato. Si noti che appaiono tutti nell'output. Ora provate questo:

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

noti che uno dei valori viene catturato da una variabile. Non appare nella pipeline di uscita.

+0

Cosa fa il foreach? Di che cosa parla? –

+14

Una soluzione migliore è usare select-object -expand FullName –

+0

FYI, è possibile assegnare una variabile _and_ emit all'output usando 'tee-object'. Esempio: 'ls | select -primo nome -proprietà completo | % {$ _. FullName} | tee -variable firstpath' –

7

per la domanda # 1

Ho rimosso "select-oggetto" parte - è ridondante e spostato "dove" filtro prima "foreach" a differenza dangph's answer - Filtrare il più presto possibile in modo che si sta trattando solo un sottoinsieme di ciò che devi affrontare nella prossima pipe line.

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

Questo frammento di codice legge essenzialmente

  • ottenere tutti i file il percorso completo di tutti i file in modo ricorsivo (Get-ChildItem directory $ -Recurse)
  • Filter le directory (Where-Object {! $ _ .PsIsContainer})
  • Ritorna il nome del file completo soltanto (foreach {$ _. FullName})
  • Salvare tutti i nomi dei file in $ file

Si noti che per foreach {$ _. FullName}, in PowerShell, ultima istruzione in un blocco di script ({...}) viene restituito, in questo caso $ _. FullName di tipo stringa

Se hai davvero bisogno di ottenere un oggetto grezzo, non devi fare nulla dopo esserti sbarazzato di "select-object". Se si dovesse utilizzare Select-Object ma si desidera accedere all'oggetto non elaborato, utilizzare "PsBase", che è una domanda completamente diversa (argomento) - Fare riferimento a "What's up with PSBASE, PSEXTENDED, PSADAPTED, and PSOBJECT?" per ulteriori informazioni su tale argomento

Per Domanda n. 2

e filtraggio anche da $ _ PsIsContainer significa che state escludendo un contenitore di oggetti di livello -!. Nel tuo caso, si sta facendo Get-ChildItem su un FileSystem fornitore (si può vedere provider PowerShell tramite Get-PsProvider), quindi il contenitore è DirectoryInfo (cartella)

PsIsContainer significa cose diverse in diversi provider PowerShell; per esempio) Per Registro fornitore, PsIsContainer è di tipo Microsoft.Win32.RegistryKey Prova questa:

>pushd HKLM:\SOFTWARE 
>ls | gm 

[UPDATE] alla seguente domanda: Cosa fa il foreach fare? Di che cosa parla? Per chiarire, "foreach" è un alias per "Foreach-Object" Si può scoprire attraverso,

get-help foreach 

- o -

get-alias foreach 

Ora nella mia risposta, "foreach "sta enumerando ogni istanza di oggetto di tipo FileInfo restituita dalla pipe precedente (che ha le directory filtrate). FileInfo ha una proprietà denominata FullName e questo è ciò che "foreach" sta elencando.
E l'oggetto di riferimento è passato attraverso la pipeline tramite una variabile speciale della pipeline denominata "$ _" che è di tipo FileInfo all'interno del contesto del blocco di script di "foreach".

+0

Cosa fa il foreach? Di che cosa parla? –

+0

Lasciatemi aggiornare la risposta – Sung

14

Per ottenere la stringa per il nome del file è possibile utilizzare

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

Il parametro -ExpandProperty consente di ottenere indietro un oggetto in base al tipo della proprietà specificata.

Ulteriori test dimostrano che questo non ha funzionato con V1, ma che la funzionalità è fissa a partire dalla V2 CTP3.

3

Per V1, aggiungere il seguente filtro al profilo:

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

allora si può fare questo:

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

A proposito, se si utilizza il PowerShell Community Extensions che già hanno questa.

Per quanto riguarda la possibilità di utilizzare Select-Object -Expand in V2, è un trucco carino ma non ovvio e in realtà non è ciò per cui Select-Object e -Expand erano destinati. -Espand è tutto appiattito come SelectMany di LINQ e Select-Object riguarda la proiezione di più proprietà su un oggetto personalizzato.

Problemi correlati