この答えはあなたのためではありません:
-まれに、外部CLIを使用する必要はめったにありません(一般的に努力する価値があります-PowerShellネイティブコマンドは一緒に非常によく機能し、そのような機能は必要ありません)。
-Bashのプロセス置換に慣れていない。
この回答は、次の場合に
役立ちます。-頻繁に外部CLIを使用する(習慣ではないか、(良い)PowerShellネイティブの代替がないため)、特にスクリプトを作成するとき。
-Bashのプロセス置換ができることに慣れており、感謝しています。
- 更新:PowerShellがUnixプラットフォームでもサポートされるようになったため、この機能への関心が高まっています。GitHubでこの機能のリクエストをご覧ください、PowerShellがプロセス置換に類似した機能を実装することを示唆しています。
Unixの世界のBash / Ksh / Zshでは、プロセス置換は、コマンド出力を、それ自体をクリーンアップする一時ファイルであるかのように扱うことを提供します。例えばcat <(echo 'hello')
、コマンド出力を含む一時ファイルのパスとしてコマンドcat
からの出力を見ます。echo
PowerShellネイティブのコマンドにはこのような機能は実際には必要ありませんが、外部CLIを扱う場合には便利です。
PowerShellでこの機能をエミュレートするのは面倒ですが、頻繁に必要な場合は価値があります。
cf
スクリプトブロックを受け入れ、ブロックを実行し、その出力をtempに書き込むという名前の関数を想像してください。ファイルはオンデマンドで作成され、一時ファイルを返します。ファイルのパス ; 例えば:
findstr.exe "Windows" (cf { Get-ChildItem c:\ }) # findstr sees the temp. file's path.
これは、このような機能の必要性をうまく説明していない単純な例です。おそらくより説得力のあるシナリオは、psftp.exe
SFTP転送の使用です。バッチ(自動)使用には、目的のコマンドを含む入力ファイルを提供する必要がありますが、そのようなコマンドはオンザフライで文字列として簡単に作成できます。
外部ユーティリティと可能な限り広く互換性を保つため、temp。ファイルはデフォルトでBOM(バイトオーダーマーク)なしのUTF-8エンコーディングを使用する必要がありますが-BOM
、必要に応じてUTF-8 BOMをリクエストできます。
残念ながら、プロセス置換の自動クリーンアップの側面は直接エミュレートできないため、明示的なクリーンアップコールが必要です。クリーンアップは、cf
引数なしで呼び出すことにより実行されます。
以下のための対話型の使用、あなたができるあなたにクリーンアップコールを追加することにより、クリーンアップを自動化するprompt
(次のように機能prompt
関数はプロンプトを返す文字列を、だけでなく、舞台裏を実行するために使用することができますがバッシュのに似たプロンプトが表示されるたびに、コマンド$PROMPT_COMMAND
変数); インタラクティブセッションで使用できるcf
ようにするには、PowerShellプロファイルに次の定義と以下の定義を追加します。
"function prompt { cf 4>`$null; $((get-item function:prompt).definition) }" |
Invoke-Expression
スクリプトで使用する場合、クリーンアップが実行されるようにするには、使用するブロック(場合によってはcf
スクリプト全体)をtry
/ finally
ブロックでラップする必要があり、cf
引数なしでクリーンアップのために呼び出されます。
# 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.
}
ここだ実装は:高度な機能ConvertTo-TempFile
とその簡潔別名、cf
:
注:の使用によりNew-Module
PSv3 +が必要になり、動的モジュールを介して関数が定義され、関数パラメーターと、渡されたスクリプトブロック内で参照される変数の間に変数の競合がなくなります。
$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
}
}
}
オプションで出力[ファイル]パスやファイル拡張子を指定できることに注意してください。