Out-File
parece forçar a lista técnica ao usar UTF-8:
$MyFile = Get-Content $MyPath
$MyFile | Out-File -Encoding "UTF8" $MyPath
Como gravar um arquivo em UTF-8 sem BOM usando o PowerShell?
encoding
powershell
utf-8
byte-order-mark
M. Dudley
fonte
fonte
Respostas:
Usar a
UTF8Encoding
classe do .NET e passar$False
para o construtor parece funcionar:fonte
[System.IO.File]::WriteAllLines($MyPath, $MyFile)
é suficiente. EssaWriteAllLines
sobrecarga grava exatamente UTF8 sem BOM.WriteAllLines
parece exigir$MyPath
ser absoluto.WriteAllLines
obtém o diretório atual de[System.Environment]::CurrentDirectory
. Se você abrir o PowerShell e alterar o diretório atual (usandocd
ouSet-Location
),[System.Environment]::CurrentDirectory
não será alterado e o arquivo acabará no diretório errado. Você pode contornar isso por[System.Environment]::CurrentDirectory = (Get-Location).Path
.A maneira correta a partir de agora é usar uma solução recomendada por @Roman Kuzmin nos comentários para @M. Dudley responde :
(Também reduzi um pouco removendo os
System
esclarecimentos desnecessários do espaço para nome - ele será substituído automaticamente por padrão.)fonte
[IO.File]::WriteAllLines(($filename | Resolve-Path), $content)
Achei que isso não seria UTF, mas acabei de encontrar uma solução bastante simples que parece funcionar ...
Para mim, isso resulta em um utf-8 sem arquivo bom, independentemente do formato de origem.
fonte
-encoding utf8
para minha exigência.-Encoding ASCII
evita o problema da lista técnica, mas obviamente você recebe apenas caracteres ASCII de 7 bits . Como o ASCII é um subconjunto do UTF-8, o arquivo resultante também é tecnicamente um arquivo UTF-8 válido, mas todos os caracteres não ASCII da sua entrada serão convertidos em?
caracteres literais .-encoding utf8
ainda gera UTF-8 com uma BOM. :(Nota: Esta resposta se aplica ao Windows PowerShell ; por outro lado, na edição do PowerShell Core para várias plataformas (v6 +), UTF-8 sem BOM é a codificação padrão em todos os cmdlets.
Em outras palavras: se você estiver usando o PowerShell [Core] versão 6 ou superior , por padrão , você obtém arquivos UTF-8 sem BOM (que você também pode solicitar explicitamente com
-Encoding utf8
/-Encoding utf8NoBOM
, enquanto que com a codificação -BOM-utf8BOM
).Para complementar a resposta simples e pragmática de M. Dudley (e a reformulação mais concisa do ForNeVeR ):
Por conveniência, aqui está a função avançada
Out-FileUtf8NoBom
, uma alternativa baseada em pipeline que imitaOut-File
, o que significa:Out-File
em um pipeline.Out-File
.Exemplo:
Observe como
(Get-Content $MyPath)
está incluído(...)
, o que garante que o arquivo inteiro seja aberto, lido na íntegra e fechado antes de enviar o resultado pelo pipeline. Isso é necessário para poder gravar novamente no mesmo arquivo (atualize-o no local ).Geralmente, porém, essa técnica não é aconselhável por 2 motivos: (a) o arquivo inteiro deve caber na memória e (b) se o comando for interrompido, os dados serão perdidos.
Uma observação sobre o uso da memória :
Código fonte de
Out-FileUtf8NoBom
(também disponível como um Gist licenciado pelo MIT ):fonte
A partir da versão 6, o powershell suporta a
UTF8NoBOM
codificação para conteúdo definido e arquivo externo e até a usa como codificação padrão.Portanto, no exemplo acima, deve ser simplesmente assim:
fonte
$PSVersionTable.PSVersion
Ao usar em
Set-Content
vez deOut-File
, você pode especificar a codificaçãoByte
, que pode ser usada para gravar uma matriz de bytes em um arquivo. Isso em combinação com uma codificação UTF8 personalizada que não emite a lista técnica fornece o resultado desejado:A diferença de usar
[IO.File]::WriteAllLines()
ou semelhante é que ele deve funcionar bem com qualquer tipo de item e caminho, não apenas os caminhos reais do arquivo.fonte
Esse script converterá, para UTF-8 sem BOM, todos os arquivos .txt no DIRECTORY1 e os produzirá em DIRECTORY2
fonte
Origem Como remover UTF8 Byte Order Mark (BOM) de um arquivo usando o PowerShell
fonte
Se você deseja usar
[System.IO.File]::WriteAllLines()
, deve converter o segundo parâmetro paraString[]
(se o tipo de$MyFile
forObject[]
) e também especificar o caminho absoluto com$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($MyPath)
, como:Se você deseja usar
[System.IO.File]::WriteAllText()
, algumas vezes você deve canalizar o segundo parâmetro| Out-String |
para adicionar CRLFs ao final de cada linha explicitamente (especialmente quando você os usaConvertTo-Csv
):Ou você pode usar
[Text.Encoding]::UTF8.GetBytes()
comSet-Content -Encoding Byte
:consulte: Como gravar o resultado do ConvertTo-Csv em um arquivo no UTF-8 sem BOM
fonte
$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($MyPath)
éConvert-Path $MyPath
; se você deseja garantir um CRLF à direita, basta usar[System.IO.File]::WriteAllLines()
mesmo com uma única sequência de entrada (não é necessárioOut-String
).Uma técnica que utilizo é redirecionar a saída para um arquivo ASCII usando o cmdlet Out-File .
Por exemplo, geralmente executo scripts SQL que criam outro script SQL para executar no Oracle. Com o redirecionamento simples (">"), a saída será em UTF-16, que não é reconhecida pelo SQLPlus. Para contornar isso:
O script gerado pode ser executado através de outra sessão do SQLPlus sem preocupações com o Unicode:
fonte
-Encoding ASCII
evita o problema da lista técnica, mas obviamente você só obtém suporte para caracteres ASCII de 7 bits . Como o ASCII é um subconjunto do UTF-8, o arquivo resultante também é tecnicamente um arquivo UTF-8 válido, mas todos os caracteres não ASCII da sua entrada serão convertidos em?
caracteres literais .Altere vários arquivos por extensão para UTF-8 sem BOM:
fonte
Por qualquer motivo, as
WriteAllLines
chamadas ainda estavam produzindo uma lista técnica para mim, com oUTF8Encoding
argumento BOMless e sem ele. Mas o seguinte funcionou para mim:Eu tive que tornar o caminho do arquivo absoluto para que ele funcionasse. Caso contrário, ele gravou o arquivo na minha área de trabalho. Além disso, suponho que isso funcione apenas se você souber que sua lista técnica é de 3 bytes. Não tenho idéia de quão confiável é esperar um determinado formato / comprimento de lista técnica com base na codificação.
Além disso, conforme escrito, isso provavelmente só funcionará se o arquivo se encaixar em uma matriz do PowerShell, que parece ter um limite de tamanho de algum valor menor do que
[int32]::MaxValue
na minha máquina.fonte
WriteAllLines
sem um argumento de codificação nunca grava uma BOM propriamente dita , mas é concebível que sua string tenha começado com o caractere BOM (U+FEFF
), que ao escrever efetivamente criou uma BOM UTF-8; por exemplo:$s = [char] 0xfeff + 'hi'; [io.file]::WriteAllText((Convert-Path t.txt), $s)
(omita o[char] 0xfeff +
para ver que nenhuma lista técnica é gravada).[Environment]::CurrentDirectory = $PWD.ProviderPath
, ou, como uma alternativa mais genérica à sua"$(pwd)\..."
abordagem (melhor:"$pwd\..."
, ainda melhor:"$($pwd.ProviderPath)\..."
ou(Join-Path $pwd.ProviderPath ...)
), o uso(Convert-Path BOMthetorpedoes.txt)
U+FEFF
abstrato .Poderia usar abaixo para obter UTF8 sem BOM
fonte
ASCII
não é UTF-8, mas também não é a página de código ANSI atual - você está pensandoDefault
;ASCII
verdadeiramente é a codificação ASCII de 7 bits, com pontos de código> = 128 sendo convertidos em?
instâncias literais .-Encoding ASCII
se realmente é apenas ASCII de 7 bits:'äb' | out-file ($f = [IO.Path]::GetTempFilename()) -encoding ASCII; '?b' -eq $(Get-Content $f; Remove-Item $f)
- oä
foi transliterado para a?
. Por outro lado,-Encoding Default
("ANSI") a preservaria corretamente.Este funciona para mim (use "Padrão" em vez de "UTF8"):
O resultado é ASCII sem BOM.
fonte
Default
codificação usará a página de código ANSI atual do sistema, que não é UTF-8, conforme necessário.