注:この回答はWindowsPowerShellに適用されます。対照的に、クロスプラットフォームのPowerShell Coreエディション(v6 +)では、すべてのコマンドレットで、BOMなしのUTF-8がデフォルトのエンコーディングです。
つまり、 PowerShell [Core]バージョン6以降を使用している場合、デフォルトでBOMのないUTF-8ファイルを取得します-Encoding utf8
(これは/で明示的に要求することもできますが、 -BOMエンコーディングで-Encoding utf8NoBOM
取得することもできます)。-utf8BOM
Windows 10を実行していて、システム全体でBOMなしのUTF-8エンコーディングに切り替えたい場合は、副作用が発生する可能性があります。WindowsPowerShellでもBOMなしのUTF-8を一貫して使用することができます。これを参照してください。答え。
M.ダドリー自身の単純で実用的な答え(およびForNeVeRのより簡潔な再定式化)を補完するために:
便宜上、ここに高度な関数Out-FileUtf8NoBom
があります。これは、を模倣するパイプラインベースの代替Out-File
手段です。つまり、次のことを意味します。
Out-File
パイプラインのように使用できます。
- 文字列ではない入力オブジェクトは、と同じように、コンソールに送信した場合と同じようにフォーマットされます
Out-File
。
- 追加の
-UseLF
スイッチを使用すると、WindowsスタイルのCRLF改行をUnixスタイルのLFのみの改行に変換できます。
例:
(Get-Content $MyPath) | Out-FileUtf8NoBom $MyPath # Add -UseLF for Unix newlines
(Get-Content $MyPath)
で囲まれていることに注意してください(...)
。これにより、パイプラインを介して結果を送信する前に、ファイル全体が開かれ、完全に読み取られ、閉じられます。これは、同じファイルに書き戻す(その場で更新する)ために必要です。
ただし、一般的に、この手法は2つの理由からお勧めできません。(a)ファイル全体がメモリに収まる必要があり、(b)コマンドが中断されると、データが失われます。
メモリ使用に関する注意:
- M. Dudley自身の答えでは、最初にファイルの内容全体をメモリに構築する必要があります。これは、大きなファイルでは問題になる可能性があります。
- 以下の関数はこれをわずかに改善します。すべての入力オブジェクトは最初にバッファリングされますが、それらの文字列表現が生成され、出力ファイルに1つずつ書き込まれます。
関数のソースコードOut-FileUtf8NoBom
:
注:この機能はMITライセンスの要点としても利用可能であり、今後も維持されます。
次のコマンドを使用して直接インストールできます(これは安全であると個人的に保証できますが、この方法で直接実行する前に、必ずスクリプトの内容を確認する必要があります)。
# Download and define the function.
irm https://gist.github.com/mklement0/8689b9b5123a9ba11df7214f82a673be/raw/Out-FileUtf8NoBom.ps1 | iex
function Out-FileUtf8NoBom {
<#
.SYNOPSIS
Outputs to a UTF-8-encoded file *without a BOM* (byte-order mark).
.DESCRIPTION
Mimics the most important aspects of Out-File:
* Input objects are sent to Out-String first.
* -Append allows you to append to an existing file, -NoClobber prevents
overwriting of an existing file.
* -Width allows you to specify the line width for the text representations
of input objects that aren't strings.
However, it is not a complete implementation of all Out-File parameters:
* Only a literal output path is supported, and only as a parameter.
* -Force is not supported.
* Conversely, an extra -UseLF switch is supported for using LF-only newlines.
Caveat: *All* pipeline input is buffered before writing output starts,
but the string representations are generated and written to the target
file one by one.
.NOTES
The raison d'être for this advanced function is that Windows PowerShell
lacks the ability to write UTF-8 files without a BOM: using -Encoding UTF8
invariably prepends a BOM.
Copyright (c) 2017, 2020 Michael Klement <mklement0@gmail.com> (http://same2u.net),
released under the [MIT license](https://spdx.org/licenses/MIT#licenseText).
#>
[CmdletBinding()]
param(
[Parameter(Mandatory, Position=0)] [string] $LiteralPath,
[switch] $Append,
[switch] $NoClobber,
[AllowNull()] [int] $Width,
[switch] $UseLF,
[Parameter(ValueFromPipeline)] $InputObject
)
#requires -version 3
# Convert the input path to a full one, since .NET's working dir. usually
# differs from PowerShell's.
$dir = Split-Path -LiteralPath $LiteralPath
if ($dir) { $dir = Convert-Path -ErrorAction Stop -LiteralPath $dir } else { $dir = $pwd.ProviderPath}
$LiteralPath = [IO.Path]::Combine($dir, [IO.Path]::GetFileName($LiteralPath))
# If -NoClobber was specified, throw an exception if the target file already
# exists.
if ($NoClobber -and (Test-Path $LiteralPath)) {
Throw [IO.IOException] "The file '$LiteralPath' already exists."
}
# Create a StreamWriter object.
# Note that we take advantage of the fact that the StreamWriter class by default:
# - uses UTF-8 encoding
# - without a BOM.
$sw = New-Object System.IO.StreamWriter $LiteralPath, $Append
$htOutStringArgs = @{}
if ($Width) {
$htOutStringArgs += @{ Width = $Width }
}
# Note: By not using begin / process / end blocks, we're effectively running
# in the end block, which means that all pipeline input has already
# been collected in automatic variable $Input.
# We must use this approach, because using | Out-String individually
# in each iteration of a process block would format each input object
# with an indvidual header.
try {
$Input | Out-String -Stream @htOutStringArgs | % {
if ($UseLf) {
$sw.Write($_ + "`n")
}
else {
$sw.WriteLine($_)
}
}
} finally {
$sw.Dispose()
}
}