Esta resposta é NÃO para você , se você:
- raramente, ou nunca, precisam usar CLIs externas (as quais geralmente valem a pena - os comandos nativos do PowerShell funcionam muito melhor juntos e não precisam de um recurso desse tipo).
- não estão familiarizados com a substituição de processos do Bash.
Esta resposta IS for you , se você:
- freqüentemente usam CLIs externos (seja por hábito ou por falta de (boas) alternativas nativas do PowerShell), especialmente ao escrever scripts.
- são usados e apreciam o que a substituição de processos do Bash pode fazer.
- Atualizar : agora que o PowerShell também é suportado em plataformas Unix, esse recurso é de interesse crescente - consulte esta solicitação de recurso no GitHub , que sugere que o PowerShell implemente um recurso semelhante ao processo de substituição.
No mundo Unix, em Bash / Ksh / Zsh, uma substituição de processo oferece tratamento de saída de comando como se fosse um arquivo temporário que é limpo após ele mesmo; por exemplo. cat <(echo 'hello')
, onde cat
vê a saída do comando echo
como o caminho de um arquivo temporário contendo a saída do comando .
Embora os comandos nativos do PowerShell não tenham necessidade real de tal recurso, ele pode ser útil ao lidar com CLIs externas .
A emulação do recurso no PowerShell é incômoda , mas pode valer a pena, se você precisar dele com frequência.
Imagine uma função chamada cf
que aceita um bloco de script, executa o bloco e grava sua saída em um temp. arquivo criado sob demanda e retorna o temp. caminho do arquivo ; por exemplo:
findstr.exe "Windows" (cf { Get-ChildItem c:\ }) # findstr sees the temp. file's path.
Este é um exemplo simples que não ilustra bem a necessidade para tal recurso. Talvez um cenário mais convincente seja o uso de psftp.exe
para transferências de SFTP: o uso em lote (automatizado) requer o fornecimento de um arquivo de entrada contendo os comandos desejados, enquanto tais comandos podem ser facilmente criados como uma string em tempo real.
Para ser tão compatível com utilitários externos quanto possível, a temp. O arquivo deve usar UTF-8 codificação sem BOM (marca de ordem de byte) por padrão, embora você possa solicitar uma BOM UTF-8 com -BOM
, se necessário.
Infelizmente, o aspecto automático cleanup das substituições de processos não pode ser diretamente , portanto é necessária uma chamada de limpeza explícita ; a limpeza é executada chamando cf
sem argumentos :
-
Para uso interativo , você pode automatizar a limpeza adicionando a chamada de limpeza à sua função
prompt
da seguinte forma (a funçãoprompt
retorna o prompt string , mas também pode ser usado para executar comandos por trás das cenas toda vez que o prompt é exibido, similar à variável$PROMPT_COMMAND
do Bash); para disponibilidade em qualquer sessão interativa, adicione o seguinte, bem como a definição decf
abaixo ao seu perfil do PowerShell:"function prompt { cf 4>'$null; $((get-item function:prompt).definition) }" | Invoke-Expression
-
Para usar em scripts , para garantir que a limpeza seja executada, o bloco que usa
cf
- potencialmente todo o script - precisa ser agrupado emtry
/finally
block, no qualcf
sem argumentos é chamado para limpeza:
# Example
try {
# Pass the output from 'Get-ChildItem' via a temporary file.
findstr.exe "Windows" (cf { Get-ChildItem c:\ })
# cf() will reuse the existing temp. file for additional invocations.
# Invoking it without parameters will delete the temp. file.
} finally {
cf # Clean up the temp. file.
}
Veja a implementação : função avançada ConvertTo-TempFile
e seu alias sucinto, cf
:
Nota : O uso de New-Module
, que requer PSv3 +, para definir a função através de um módulo dinâmico garante que não pode haver conflitos de variáveis entre os parâmetros da função e variáveis referenciadas dentro do bloco de script passado.
$null = New-Module { # Load as dynamic module
# Define a succinct alias.
set-alias cf ConvertTo-TempFile
function ConvertTo-TempFile {
[CmdletBinding(DefaultParameterSetName='Cleanup')]
param(
[Parameter(ParameterSetName='Standard', Mandatory=$true, Position=0)]
[ScriptBlock] $ScriptBlock
, [Parameter(ParameterSetName='Standard', Position=1)]
[string] $LiteralPath
, [Parameter(ParameterSetName='Standard')]
[string] $Extension
, [Parameter(ParameterSetName='Standard')]
[switch] $BOM
)
$prevFilePath = Test-Path variable:__cttfFilePath
if ($PSCmdlet.ParameterSetName -eq 'Cleanup') {
if ($prevFilePath) {
Write-Verbose "Removing temp. file: $__cttfFilePath"
Remove-Item -ErrorAction SilentlyContinue $__cttfFilePath
Remove-Variable -Scope Script __cttfFilePath
} else {
Write-Verbose "Nothing to clean up."
}
} else { # script block specified
if ($Extension -and $Extension -notlike '.*') { $Extension = ".$Extension" }
if ($LiteralPath) {
# Since we'll be using a .NET framework classes directly,
# we must sync .NET's notion of the current dir. with PowerShell's.
[Environment]::CurrentDirectory = $pwd
if ([System.IO.Directory]::Exists($LiteralPath)) {
$script:__cttfFilePath = [IO.Path]::Combine($LiteralPath, [IO.Path]::GetRandomFileName() + $Extension)
Write-Verbose "Creating file with random name in specified folder: '$__cttfFilePath'."
} else { # presumptive path to a *file* specified
if (-not [System.IO.Directory]::Exists((Split-Path $LiteralPath))) {
Throw "Output folder '$(Split-Path $LiteralPath)' must exist."
}
$script:__cttfFilePath = $LiteralPath
Write-Verbose "Using explicitly specified file path: '$__cttfFilePath'."
}
} else { # Create temp. file in the user's temporary folder.
if (-not $prevFilePath) {
if ($Extension) {
$script:__cttfFilePath = [IO.Path]::Combine([IO.Path]::GetTempPath(), [IO.Path]::GetRandomFileName() + $Extension)
} else {
$script:__cttfFilePath = [IO.Path]::GetTempFilename()
}
Write-Verbose "Creating temp. file: $__cttfFilePath"
} else {
Write-Verbose "Reusing temp. file: $__cttfFilePath"
}
}
if (-not $BOM) { # UTF8 file *without* BOM
# Note: Out-File, sadly, doesn't support creating UTF8-encoded files
# *without a BOM*, so we must use the .NET framework.
# [IO.StreamWriter] by default writes UTF-8 files without a BOM.
$sw = New-Object IO.StreamWriter $__cttfFilePath
try {
. $ScriptBlock | Out-String -Stream | % { $sw.WriteLine($_) }
} finally { $sw.Close() }
} else { # UTF8 file *with* BOM
. $ScriptBlock | Out-File -Encoding utf8 $__cttfFilePath
}
return $__cttfFilePath
}
}
}
Observe a capacidade de especificar opcionalmente um caminho de saída [arquivo] e / ou extensão de nome de arquivo.