Jawaban ini BUKAN untuk Anda , jika Anda:
- jarang, jika pernah, perlu menggunakan CLI eksternal (yang umumnya layak diperjuangkan - perintah PowerShell-asli bermain lebih baik bersama-sama dan tidak memerlukan fitur seperti itu).
- tidak terbiasa dengan proses substitusi Bash.
Jawaban ini ADALAH untuk Anda , jika Anda:
- sering menggunakan CLI eksternal (apakah karena kebiasaan atau karena kurangnya (baik) alternatif PowerShell-asli), terutama saat menulis skrip.
- Digunakan untuk dan menghargai apa yang bisa dilakukan oleh proses substitusi Bash.
- Pembaruan : Sekarang PowerShell didukung pada platform Unix juga, fitur ini semakin menarik - lihat permintaan fitur ini di GitHub, yang menunjukkan bahwa PowerShell mengimplementasikan fitur yang mirip dengan proses substitusi.
Di dunia Unix, di Bash / Ksh / Zsh, subtitusi proses menawarkan memperlakukan output perintah seolah-olah itu adalah file sementara yang membersihkan setelah itu sendiri; misalnya cat <(echo 'hello')
, di mana cat
melihat output dari echo
perintah sebagai jalur file sementara yang berisi output perintah .
Sementara perintah PowerShell-asli tidak membutuhkan fitur seperti itu, itu bisa berguna ketika berhadapan dengan CLI eksternal .
Meniru fitur di PowerShell rumit , tetapi mungkin sepadan, jika Anda sering membutuhkannya.
Bayangkan sebuah fungsi bernama cf
yang menerima blok skrip, menjalankan blok dan menulis hasilnya ke temp. file dibuat sesuai permintaan, dan mengembalikan temp. jalur file ; misalnya:
findstr.exe "Windows" (cf { Get-ChildItem c:\ }) # findstr sees the temp. file's path.
Ini adalah contoh sederhana yang tidak menggambarkan perlunya fitur tersebut dengan baik. Mungkin skenario yang lebih meyakinkan adalah penggunaan psftp.exe
untuk transfer SFTP: penggunaan batch-nya (otomatis) mengharuskan menyediakan file input yang berisi perintah yang diinginkan, sedangkan perintah seperti itu dapat dengan mudah dibuat sebagai string dengan cepat.
Agar kompatibel dengan utilitas eksternal sebanyak mungkin, temp. file harus menggunakan UTF-8 encoding tanpa BOM (byte-order mark) secara default, meskipun Anda dapat meminta BOM UTF-8 dengan -BOM
, jika diperlukan.
Sayangnya, aspek pembersihan otomatis dari substitusi proses tidak dapat ditiru secara langsung , sehingga diperlukan panggilan pembersihan secara eksplisit ; pembersihan dilakukan dengan memanggil cf
tanpa argumen :
Untuk penggunaan interaktif , Anda dapat mengotomatiskan pembersihan dengan menambahkan panggilan pembersihan ke prompt
fungsi Anda sebagai berikut ( prompt
fungsi mengembalikan string prompt , tetapi juga dapat digunakan untuk melakukan perintah di belakang layar setiap kali prompt ditampilkan, mirip dengan Bash's $PROMPT_COMMAND
variabel); untuk ketersediaan dalam sesi interaktif apa pun, tambahkan berikut ini serta definisi di cf
bawah ini untuk profil PowerShell Anda:
"function prompt { cf 4>`$null; $((get-item function:prompt).definition) }" |
Invoke-Expression
Untuk digunakan dalam skrip , untuk memastikan bahwa pembersihan dilakukan, blok yang menggunakan cf
- berpotensi keseluruhan skrip - perlu dibungkus dengan try
/ finally
blok, di mana cf
tanpa argumen dipanggil untuk pembersihan:
# 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.
}
Inilah implementasinya : fungsi lanjutan ConvertTo-TempFile
dan alias ringkasnya cf
:
Catatan : Penggunaan New-Module
, yang membutuhkan PSv3 +, untuk mendefinisikan fungsi melalui modul dinamis memastikan bahwa tidak ada konflik variabel antara parameter fungsi dan variabel yang dirujuk di dalam blok skrip yang diteruskan.
$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
}
}
}
Perhatikan kemampuan untuk secara opsional menentukan jalur [file] keluaran dan / atau ekstensi nama file.