Wie schreibe ich ein PowerShell-Skript, das Pipeline-Eingaben akzeptiert?

75

Ich versuche, ein PowerShell-Skript zu schreiben, das Pipeline-Eingaben erhalten kann (und dies voraussichtlich tun wird), versuche aber etwas Ähnliches

ForEach-Object {
   # do something
}

funktioniert nicht wirklich, wenn das Skript über die Befehlszeile wie folgt verwendet wird:

1..20 | .\test.ps1

Gibt es einen Weg?

Hinweis: Ich kenne Funktionen und Filter. Das ist nicht was ich suche.

Joey
quelle

Antworten:

42

Dies funktioniert und es gibt wahrscheinlich andere Möglichkeiten, dies zu tun:

foreach ($i in $input) {
    $i
}

17:12:42 PS> 1..20 | . \ cmd-input.ps1
1
2
3
- snip -
18
19
20

Suchen Sie nach "Powershell $ Eingabevariable" und Sie finden weitere Informationen und Beispiele.
Ein paar sind da:
PowerShell-Funktionen und Filter PowerShell Pro!
(Siehe Abschnitt "Verwenden der PowerShell-Spezialvariablen" $ input "")
"Skripte, Funktionen und Skriptblöcke haben alle Zugriff auf die $ input-Variable, die einen Enumerator über die Elemente in der eingehenden Pipeline bereitstellt."
oder
$ input gotchas «Dmitrys PowerBlog PowerShell und darüber hinaus
" ... im Grunde $ Eingabe in einen Enumerator, der Zugriff auf die Pipeline bietet, die Sie haben. "

Für die PS-Befehlszeile nicht die DOS-Befehlszeile Windows Command Processor.

Bratch
quelle
Zeit für ein wenig Nekro ... nur für alle, die mitwandern und dies lesen, ist DOS weiterhin für jede Windows-Version verfügbar. 64 Bit oder 32 Bit.
EBGreen
13
EBGreen, ntvdmdie DOS-VM von Windows NT, ist auf 64-Bit-Systemen nicht mehr vorhanden. cmd.exeist nicht DOS; Es ist der Windows-Befehlsprozessor und hat abgesehen von grauem Text auf Schwarz überhaupt nichts mit DOS zu tun.
Joey
117

In Version 2 können Sie auch Pipeline-Eingaben akzeptieren (nach propertyName oder byValue), Parameter-Aliase hinzufügen usw.:

function Get-File{
    param(  
    [Parameter(
        Position=0, 
        Mandatory=$true, 
        ValueFromPipeline=$true,
        ValueFromPipelineByPropertyName=$true)
    ]
    [Alias('FullName')]
    [String[]]$FilePath
    ) 

    process {
       foreach($path in $FilePath)
       {
           Write-Host "file path is: $path"
       }
    }
}


# test ValueFromPipelineByPropertyName 
dir | Get-File

# test ValueFromPipeline (byValue) 

"D:\scripts\s1.txt","D:\scripts\s2.txt" | Get-File

 - or -

dir *.txt | foreach {$_.fullname} | Get-File
Shay Levy
quelle
Immer noch eine Funktion, kein Skript. Siehe den Kommentar zu stackoverflow.com/questions/885349/… .
Joey
6
Kein Problem, speichern Sie den Funktionskörper in einer Skriptdatei und leiten Sie ihn an das Skript weiter: dir | . \ Get-File.ps1
Shay Levy
7
Tatsächlich können Sie den param () -Block oben im Skript einfügen, ohne eine lokale Funktion für das Skript zu deklarieren.
Thomas S. Trias
24

Sie können entweder einen Filter schreiben, der ein Sonderfall einer Funktion wie der folgenden ist:

filter SquareIt([int]$num) { $_ * $_ }

oder Sie können eine ähnliche Funktion wie folgt erstellen:

function SquareIt([int]$num) {
  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    $_ * $_
  }

  End {
    # Executes once after last pipeline object is processed
  }
}

Das Obige funktioniert als interaktive Funktionsdefinition oder wenn in einem Skript in Ihrer globalen Sitzung (oder einem anderen Skript) gepunktet werden kann. In Ihrem Beispiel wurde jedoch angegeben, dass Sie ein Skript wünschen, sodass es sich hier um ein Skript handelt, das direkt verwendet werden kann (keine Punktierung erforderlich):

  --- Contents of test.ps1 ---
  param([int]$num)

  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    $_ * $_
  }

  End {
    # Executes once after last pipeline object is processed
  }

Mit PowerShell V2 ändert sich dies ein wenig mit "erweiterten Funktionen", die Funktionen mit denselben Parameterbindungsfunktionen wie kompilierte Cmdlets enthalten. In diesem Blogbeitrag finden Sie ein Beispiel für die Unterschiede. Beachten Sie auch, dass Sie in diesem Fall mit erweiterten Funktionen nicht $ _ verwenden, um auf das Pipeline-Objekt zuzugreifen. Mit erweiterten Funktionen werden Pipeline-Objekte wie bei einem Cmdlet an einen Parameter gebunden.

Keith Hill
quelle
Ich kenne mich mit Filtern aus, wollte aber das Skript als Element in einer Pipeline verwenden, nicht als im Skript definierte Funktion. Trotzdem danke.
Joey
4
Der Prozessblock ist das, was Sie wollen. Es hat den Vorteil, dass die Pipeline nicht aufgehalten wird.
JasonMArcher
Wenn Sie einen Parameter angeben, sollten Sie ihn verwenden. Ich dachte, es sei Teil einer Art Parameterprototyp und fragte mich, warum es nicht verwendet wurde oder ob es anstelle von DIESEM verwendet werden könnte. Verschwendete Zyklen. Immer noch wie die Antwort;)
Gerard ONeill
8

Das Folgende sind die einfachsten möglichen Beispiele für Skripte / Funktionen, die Piped-Eingaben verwenden. Jedes verhält sich wie das Weiterleiten an das Cmdlet "echo".

Als Skripte:

# Echo-Pipe.ps1
  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    echo $_
  }

  End {
    # Executes once after last pipeline object is processed
  }
# Echo-Pipe2.ps1
foreach ($i in $input) {
    $i
}

Als Funktionen:

Function Echo-Pipe {
  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    echo $_
  }

  End {
    # Executes once after last pipeline object is processed
  }
}

Function Echo-Pipe2 {
    foreach ($i in $input) {
        $i
    }
}

Z.B

PS > . theFileThatContainsTheFunctions.ps1 # This includes the functions into your session
PS > echo "hello world" | Echo-Pipe
hello world
PS > cat aFileWithThreeTestLines.txt | Echo-Pipe2
The first test line
The second test line
The third test line
samthebest
quelle
Warum eine Antwort wiederholen, die Keith bereits vor zwei Jahren gegeben hat?
Joey
Seine Antwort enthält die folgenden Probleme: Sie enthält nicht genau das, was zur Beantwortung der Frage erforderlich ist - die Quadratur ist stumpf. Die Funktionsparameter werden nicht benötigt, wir können einfach $ _ verwenden. "Sie können entweder einen Filter schreiben, der ein Sonderfall einer solchen Funktion ist" - ist grammatikalisch nicht sinnvoll und die Verwendung von Filtern ist nicht erforderlich.
Samthebest
Das hat bei mir auf Ubuntu funktioniert. Antworten oben nicht.
n.podbielski