Ця відповідь НЕ для вас , якщо ви:
- рідко, якщо взагалі колись, потрібно використовувати зовнішні CLI (до чого, як правило, варто прагнути - рідні команди PowerShell грають набагато краще разом і не потребують такої функції).
- не знайомі з заміною процесу Баша.
Ця відповідь є для вас , якщо ви:
- часто використовуйте зовнішні CLI (чи то за звичкою, чи через відсутність (хороших) альтернатив PowerShell), особливо під час написання сценаріїв.
- звикли і цінують те, що може замінити процес Баша.
- Оновлення : Тепер, коли PowerShell підтримується і на платформах Unix, ця функція викликає все більший інтерес - див. Запит на цю функцію на GitHub, що говорить про те, що PowerShell реалізує функцію, подібну до процесу заміни.
У світі Unix, у Bash / Ksh / Zsh, відбувається заміна процесу пропонує обробку командного виводу так, ніби це був тимчасовий файл, який очищається після себе; наприклад cat <(echo 'hello')
, де cat
бачить вихід з echo
команди як шлях тимчасового файлу, що містить вихід команди .
Незважаючи на те, що вбудовані PowerShell команди не мають реальної потреби в такій функції, це може бути зручно при роботі із зовнішніми CLI .
Емуляція функції в PowerShell є громіздкою , але, можливо, варто того, якщо ви часто потребуєте її.
Зображте функцію, названу, cf
яка приймає блок скриптів, виконує блок і записує його вихід у темп. файл, створений на вимогу, і повертає темп. шлях файлу ; наприклад:
findstr.exe "Windows" (cf { Get-ChildItem c:\ }) # findstr sees the temp. file's path.
Це простий приклад, який не ілюструє необхідність такої функції. Можливо, більш переконливим є сценарій використання psftp.exe
SFTP-передач: його пакетне (автоматизоване) використання вимагає надання вхідного файлу, що містить бажані команди, тоді як такі команди можуть бути легко створені у вигляді рядка на льоту.
Щоб максимально сумісна з зовнішніми утилітами, темп. Файл повинен використовувати UTF-8 кодування без BOM (мітка порядку байтів) за замовчуванням, хоча ви можете запросити BOM UTF-8 з -BOM
, якщо це необхідно.
На жаль, аспект автоматичної очистки підстановок процесу не може бути безпосередньо емульований, тому необхідний чіткий виклик очищення ; прибирання виконується зателефонувавшиcf
без аргументів :
Для інтерактивного використання ви можете автоматизувати очищення, додавши виклик очищення до своєї prompt
функції наступним чином ( prompt
функція повертає рядок підказок , але також може бути використана для виконання за кадром команд кожного разу, коли відображається запит, подібно до Bash$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 + для визначення функції через a динамічного модуля, гарантує, що між параметрами функції та змінними, на які посилається всередині блоку сценарію, не може бути змінних конфліктів.
$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
}
}
}
Зверніть увагу на можливість необов'язково вказати вихідний [файл] шлях та / або розширення імені файлу.