Partilhar via


about_Pipelines

Breve descrição

Combinar comandos em pipelines no PowerShell

Descrição longa

Um pipeline é uma série de comandos ligados por operadores de pipeline (|) (ASCII 124). Cada operador de pipeline envia os resultados do comando anterior para o comando seguinte.

O resultado do primeiro comando pode ser enviado para processamento como entrada para o segundo comando. E essa saída pode ser enviada para outro comando. O resultado é uma cadeia de comandos ou pipeline complexo que é composto por uma série de comandos simples.

Por exemplo,

Command-1 | Command-2 | Command-3

Neste exemplo, os objetos que Command-1 emitem são enviados para Command-2. Command-2 processa os objetos e envia-os para Command-3. Command-3 processa os objetos e envia-os pelo pipeline. Uma vez que não existem mais comandos no pipeline, os resultados são apresentados na consola do .

Num pipeline, os comandos são processados por ordem da esquerda para a direita. O processamento é processado como uma única operação e a saída é apresentada à medida que é gerada.

Eis um exemplo simples. O seguinte comando recebe o processo Bloco de notas e depois para.

Por exemplo,

Get-Process notepad | Stop-Process

O primeiro comando utiliza o Get-Process cmdlet para obter um objeto que representa o processo do Bloco de Notas. Utiliza um operador de pipeline (|) para enviar o objeto de processo para o cmdlet, o Stop-Process que interrompe o processo do Bloco de Notas. Tenha em atenção que o Stop-Process comando não tem um parâmetro Nome ou ID para especificar o processo, uma vez que o processo especificado é submetido através do pipeline.

Este exemplo de pipeline obtém os ficheiros de texto no diretório atual, seleciona apenas os ficheiros com mais de 10 000 bytes de comprimento, ordena-os por comprimento e apresenta o nome e o comprimento de cada ficheiro numa tabela.

Get-ChildItem -Path *.txt |
  Where-Object {$_.length -gt 10000} |
    Sort-Object -Property length |
      Format-Table -Property name, length

Este pipeline consiste em quatro comandos pela ordem especificada. A seguinte ilustração mostra o resultado de cada comando à medida que é transmitido para o comando seguinte no pipeline.

Get-ChildItem -Path *.txt
| (FileInfo objects for *.txt)
V
Where-Object {$_.length -gt 10000}
| (FileInfo objects for *.txt)
| (      Length > 10000      )
V
Sort-Object -Property Length
| (FileInfo objects for *.txt)
| (      Length > 10000      )
| (     Sorted by length     )
V
Format-Table -Property name, length
| (FileInfo objects for *.txt)
| (      Length > 10000      )
| (     Sorted by length     )
| (   Formatted in a table   )
V

Name                       Length
----                       ------
tmp1.txt                    82920
tmp2.txt                   114000
tmp3.txt                   114000

Utilizar pipelines

A maioria dos cmdlets do PowerShell foram concebidos para suportar pipelines. Na maioria dos casos, pode encaminhar os resultados de um cmdlet Obter para outro cmdlet do mesmo substantivo. Por exemplo, pode encaminhar a saída do Get-Service cmdlet para os Start-Service cmdlets ou Stop-Service .

Este pipeline de exemplo inicia o serviço WMI no computador:

Get-Service wmi | Start-Service

Por outro exemplo, pode encaminhar a saída de ou Get-ChildItem dentro do Get-Item fornecedor de registo do PowerShell para o New-ItemProperty cmdlet. Este exemplo adiciona uma nova entrada de registo, NoOfEmployees, com um valor de 8124, à chave de registo MyCompany .

Get-Item -Path HKLM:\Software\MyCompany |
  New-ItemProperty -Name NoOfEmployees -Value 8124

Muitos dos cmdlets utilitários, como Get-Member, Where-Object, Sort-Object, Group-Objecte Measure-Object são utilizados quase exclusivamente em pipelines. Pode encaminhar qualquer tipo de objeto para estes cmdlets. Este exemplo mostra como ordenar todos os processos no computador pelo número de identificadores abertos em cada processo.

Get-Process | Sort-Object -Property handles

Pode encaminhar objetos para os cmdlets de formatação, exportação e saída, tais como Format-List, Format-Table, Export-Clixml, Export-CSVe Out-File.

Este exemplo mostra como utilizar o Format-List cmdlet para apresentar uma lista de propriedades de um objeto de processo.

Get-Process winlogon | Format-List -Property *

Também pode encaminhar a saída de comandos nativos para cmdlets do PowerShell. Por exemplo:

PS> ipconfig.exe | Select-String -Pattern 'IPv4'

   IPv4 Address. . . . . . . . . . . : 172.24.80.1
   IPv4 Address. . . . . . . . . . . : 192.168.1.45
   IPv4 Address. . . . . . . . . . . : 100.64.108.37

Importante

Os fluxos Êxito e Erro são semelhantes aos fluxos stdin e stderr de outras shells. No entanto, o stdin não está ligado ao pipeline do PowerShell para introdução. Para obter mais informações, consulte about_Redirection.

Com um pouco de prática, verá que combinar comandos simples em pipelines poupa tempo e escrever e torna os scripts mais eficientes.

Como funcionam os pipelines

Esta secção explica como os objetos de entrada estão vinculados a parâmetros de cmdlet e processados durante a execução do pipeline.

Aceita a entrada do pipeline

Para suportar o pipelining, o cmdlet de receção tem de ter um parâmetro que aceite a entrada do pipeline. Utilize o Get-Help comando com as opções Completo ou Parâmetro para determinar que parâmetros de um cmdlet aceitam entrada de pipeline.

Por exemplo, para determinar qual dos parâmetros do cmdlet aceita a Start-Service entrada do pipeline, escreva:

Get-Help Start-Service -Full

ou

Get-Help Start-Service -Parameter *

A ajuda para o Start-Service cmdlet mostra que apenas os parâmetros InputObject e Name aceitam a entrada do pipeline.

-InputObject <ServiceController[]>
Specifies ServiceController objects representing the services to be started.
Enter a variable that contains the objects, or type a command or expression
that gets the objects.

Required?                    true
Position?                    0
Default value                None
Accept pipeline input?       True (ByValue)
Accept wildcard characters?  false

-Name <String[]>
Specifies the service names for the service to be started.

The parameter name is optional. You can use Name or its alias, ServiceName,
or you can omit the parameter name.

Required?                    true
Position?                    0
Default value                None
Accept pipeline input?       True (ByPropertyName, ByValue)
Accept wildcard characters?  false

Quando envia objetos através do pipeline para Start-Serviceo , o PowerShell tenta associar os objetos aos parâmetros InputObject e Name .

Métodos de aceitação da entrada do pipeline

Os parâmetros dos cmdlets podem aceitar a entrada do pipeline de uma de duas formas diferentes:

  • ByValue: o parâmetro aceita valores que correspondem ao tipo .NET esperado ou que podem ser convertidos nesse tipo.

    Por exemplo, o parâmetro Nome de Start-Service aceita entrada de pipeline por valor. Pode aceitar objetos de cadeia de carateres ou objetos que podem ser convertidos em cadeias.

  • ByPropertyName: o parâmetro só aceita entrada quando o objeto de entrada tem uma propriedade com o mesmo nome que o parâmetro.

    Por exemplo, o parâmetro Nome de Start-Service pode aceitar objetos que tenham uma propriedade Nome . Para listar as propriedades de um objeto, encaminhe-o para Get-Member.

Alguns parâmetros podem aceitar objetos pelo valor ou pelo nome da propriedade, facilitando a introdução do pipeline.

Enlace de parâmetros

Quando encaminha objetos de um comando para outro comando, o PowerShell tenta associar os objetos piped a um parâmetro do cmdlet de receção.

O componente de enlace de parâmetros do PowerShell associa os objetos de entrada aos parâmetros do cmdlet de acordo com os seguintes critérios:

  • O parâmetro tem de aceitar a entrada de um pipeline.
  • O parâmetro tem de aceitar o tipo de objeto que está a ser enviado ou um tipo que pode ser convertido para o tipo esperado.
  • O parâmetro não foi utilizado no comando.

Por exemplo, o Start-Service cmdlet tem muitos parâmetros, mas apenas dois deles, Name e InputObject aceitam entrada de pipeline. O parâmetro Nome utiliza cadeias de carateres e o parâmetro InputObject utiliza objetos de serviço. Por conseguinte, pode encaminhar cadeias, objetos de serviço e objetos com propriedades que podem ser convertidas em objetos de cadeia ou de serviço.

O PowerShell gere o enlace de parâmetros da forma mais eficiente possível. Não pode sugerir nem forçar o PowerShell a vincular a um parâmetro específico. O comando falha se o PowerShell não conseguir vincular os objetos tubados.

Para obter mais informações sobre a resolução de problemas de erros de enlace, veja Investigar Erros de Pipeline mais à frente neste artigo.

Processamento único de cada vez

A colocação de objetos num comando é semelhante à utilização de um parâmetro do comando para submeter os objetos. Vejamos um exemplo de pipeline. Neste exemplo, utilizamos um pipeline para apresentar uma tabela de objetos de serviço.

Get-Service | Format-Table -Property Name, DependentServices

Funcionalmente, é como utilizar o parâmetro InputObject de Format-Table para submeter a coleção de objetos.

Por exemplo, podemos guardar a coleção de serviços numa variável transmitida com o parâmetro InputObject .

$services = Get-Service
Format-Table -InputObject $services -Property Name, DependentServices

Em alternativa, podemos incorporar o comando no parâmetro InputObject .

Format-Table -InputObject (Get-Service) -Property Name, DependentServices

No entanto, há uma diferença importante. Quando encaminha vários objetos para um comando, o PowerShell envia os objetos para o comando um de cada vez. Quando utiliza um parâmetro de comando, os objetos são enviados como um único objeto de matriz. Esta pequena diferença tem consequências significativas.

Ao executar um pipeline, o PowerShell enumera automaticamente qualquer tipo que implemente a interface ou a IEnumerable respetiva contraparte genérica. Os itens enumerados são enviados através do pipeline um de cada vez. O PowerShell também enumera os tipos System.Data.DataTable através da Rows propriedade.

Existem algumas exceções à enumeração automática.

  • Tem de chamar o GetEnumerator() método para tabelas hash, tipos que implementam a interface ou a IDictionary respetiva contraparte genérica e System.Xml. Tipos de XmlNode .
  • A classe System.String implementa IEnumerable, no entanto, o PowerShell não enumera objetos de cadeia.

Nos exemplos seguintes, uma matriz e uma tabela hash são direcionadas para o cmdlet Measure-Object para contar o número de objetos recebidos da pipeline. A matriz tem vários membros e a tabela hash tem vários pares chave-valor. Apenas a matriz é enumerada uma de cada vez.

@(1,2,3) | Measure-Object
Count    : 3
Average  :
Sum      :
Maximum  :
Minimum  :
Property :
@{"One"=1;"Two"=2} | Measure-Object
Count    : 1
Average  :
Sum      :
Maximum  :
Minimum  :
Property :

Da mesma forma, se encaminhar vários objetos de processo do Get-Process cmdlet para o cmdlet, o Get-Member PowerShell envia cada objeto de processo, um de cada vez, para Get-Member. Get-Member apresenta a classe .NET (tipo) dos objetos de processo e as respetivas propriedades e métodos.

Get-Process | Get-Member
TypeName: System.Diagnostics.Process

Name      MemberType     Definition
----      ----------     ----------
Handles   AliasProperty  Handles = Handlecount
Name      AliasProperty  Name = ProcessName
NPM       AliasProperty  NPM = NonpagedSystemMemorySize
...

Nota

Get-Member elimina duplicados, pelo que, se os objetos forem todos do mesmo tipo, apenas apresenta um tipo de objeto.

No entanto, se utilizar o parâmetro InputObject de Get-Member, Get-Member recebe uma matriz de objetos System.Diagnostics.Process como uma única unidade. Apresenta as propriedades de uma matriz de objetos. (Anote o símbolo de matriz ([]) a seguir ao nome do tipo System.Object .)

Por exemplo,

Get-Member -InputObject (Get-Process)
TypeName: System.Object[]

Name               MemberType    Definition
----               ----------    ----------
Count              AliasProperty Count = Length
Address            Method        System.Object& Address(Int32 )
Clone              Method        System.Object Clone()
...

Este resultado pode não ser o pretendido. No entanto, depois de compreender, pode utilizá-lo. Por exemplo, todos os objetos de matriz têm uma propriedade Contar . Pode utilizá-lo para contar o número de processos em execução no computador.

Por exemplo,

(Get-Process).count

É importante lembrar que os objetos enviados pelo pipeline são entregues um de cada vez.

Utilizar comandos nativos no pipeline

O PowerShell permite-lhe incluir comandos externos nativos no pipeline. No entanto, é importante ter em atenção que o pipeline do PowerShell é orientado para objetos e não suporta dados de bytes não processados.

Encaminhar ou redirecionar a saída de um programa nativo que produz dados de bytes não processados converte a saída em cadeias .NET. Esta conversão pode causar danos na saída de dados não processados.

Como solução, chame os comandos nativos com cmd.exe /c ou sh -c e utilize os | operadores e > fornecidos pela shell nativa.

Investigar erros de pipeline

Quando o PowerShell não consegue associar os objetos piped a um parâmetro do cmdlet de receção, o comando falha.

No exemplo seguinte, tentamos mover uma entrada de registo de uma chave de registo para outra. O Get-Item cmdlet obtém o caminho de destino, que é depois direcionado para o Move-ItemProperty cmdlet . O Move-ItemProperty comando especifica o caminho atual e o nome da entrada de registo a mover.

Get-Item -Path HKLM:\Software\MyCompany\sales |
Move-ItemProperty -Path HKLM:\Software\MyCompany\design -Name product

O comando falha e o PowerShell apresenta a seguinte mensagem de erro:

Move-ItemProperty : The input object can't be bound to any parameters for
the command either because the command doesn't take pipeline input or the
input and its properties do not match any of the parameters that take
pipeline input.
At line:1 char:23
+ $a | Move-ItemProperty <<<<  -Path HKLM:\Software\MyCompany\design -Name p

Para investigar, utilize o Trace-Command cmdlet para rastrear o componente de enlace de parâmetros do PowerShell. O exemplo seguinte rastreia o enlace de parâmetros enquanto o pipeline está a ser executado. O parâmetro PSHost apresenta os resultados do rastreio na consola e o parâmetro FilePath envia os resultados do rastreio para o debug.txt ficheiro para referência posterior.

Trace-Command -Name ParameterBinding -PSHost -FilePath debug.txt -Expression {
  Get-Item -Path HKLM:\Software\MyCompany\sales |
    Move-ItemProperty -Path HKLM:\Software\MyCompany\design -Name product
}

Os resultados do rastreio são longos, mas mostram os valores que estão vinculados ao Get-Item cmdlet e, em seguida, os valores nomeados vinculados ao Move-ItemProperty cmdlet.

...
BIND NAMED cmd line args [`Move-ItemProperty`]
BIND arg [HKLM:\Software\MyCompany\design] to parameter [Path]
...
BIND arg [product] to parameter [Name]
...
BIND POSITIONAL cmd line args [`Move-ItemProperty`]
...

Por fim, mostra que a tentativa de vincular o caminho ao parâmetro Destino de Move-ItemProperty falhou.

...
BIND PIPELINE object to parameters: [`Move-ItemProperty`]
PIPELINE object TYPE = [Microsoft.Win32.RegistryKey]
RESTORING pipeline parameter's original values
Parameter [Destination] PIPELINE INPUT ValueFromPipelineByPropertyName NO
COERCION
Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName NO
COERCION
...

Utilize o Get-Help cmdlet para ver os atributos do parâmetro Destino .

Get-Help Move-ItemProperty -Parameter Destination

-Destination <String>
    Specifies the path to the destination location.

    Required?                    true
    Position?                    1
    Default value                None
    Accept pipeline input?       True (ByPropertyName)
    Accept wildcard characters?  false

Os resultados mostram que o Destino utiliza a entrada do pipeline apenas "pelo nome da propriedade". Por conseguinte, o objeto piped tem de ter uma propriedade denominada Destino.

Utilize Get-Member para ver as propriedades do objeto proveniente de Get-Item.

Get-Item -Path HKLM:\Software\MyCompany\sales | Get-Member

O resultado mostra que o item é um objeto Microsoft.Win32.RegistryKey que não tem uma propriedade Destino . Isto explica porque é que o comando falhou.

O parâmetro Path aceita a entrada do pipeline por nome ou por valor.

Get-Help Move-ItemProperty -Parameter Path

-Path <String[]>
    Specifies the path to the current location of the property. Wildcard
    characters are permitted.

    Required?                    true
    Position?                    0
    Default value                None
    Accept pipeline input?       True (ByPropertyName, ByValue)
    Accept wildcard characters?  true

Para corrigir o comando, temos de especificar o destino no Move-ItemProperty cmdlet e utilizá-lo Get-Item para obter o Caminho do item que pretendemos mover.

Por exemplo,

Get-Item -Path HKLM:\Software\MyCompany\design |
Move-ItemProperty -Destination HKLM:\Software\MyCompany\sales -Name product

Continuação de linha intrínseca

Como já foi abordado, um pipeline é uma série de comandos ligados por operadores de pipeline (|), normalmente escritos numa única linha. No entanto, para legibilidade, o PowerShell permite-lhe dividir o pipeline por várias linhas. Quando um operador de pipe é o último token na linha, o analisador do PowerShell associa a linha seguinte ao comando atual para continuar a construção do pipeline.

Por exemplo, o seguinte pipeline de linha única:

Command-1 | Command-2 | Command-3

pode ser escrito como:

Command-1 |
    Command-2 |
    Command-3

Os espaços à esquerda nas linhas subsequentes não são significativos. O avanço melhora a legibilidade.

O PowerShell 7 adiciona suporte para a continuação de pipelines com o caráter de pipeline no início de uma linha. Os exemplos seguintes mostram como pode utilizar esta nova funcionalidade.

# Wrapping with a pipe at the beginning of a line (no backtick required)
Get-Process | Where-Object CPU | Where-Object Path
    | Get-Item | Where-Object FullName -match "AppData"
    | Sort-Object FullName -Unique

# Wrapping with a pipe on a line by itself
Get-Process | Where-Object CPU | Where-Object Path
    |
    Get-Item | Where-Object FullName -match "AppData"
    |
    Sort-Object FullName -Unique

Importante

Ao trabalhar interativamente na shell, colar código com pipelines no início de uma linha apenas quando utilizar Ctrl+V para colar. Clique com o botão direito do rato em colar operações para inserir as linhas uma de cada vez. Uma vez que a linha não termina com um caráter de pipeline, o PowerShell considera que a entrada está concluída e executa essa linha conforme introduzido.

Ver também