PowerShell:使用UTF8编码而不带BOM替换单词并设置内容

3
我希望将csv文件中的\转义为\\,以便上传到Redshift。下面的PowerShell脚本可以将$TargetWord \替换为$ReplaceWord \\,但导出utf-8带有bom有时会导致Redshift复制错误。欢迎提供任何建议来改进它。谢谢您的帮助。

Exp_Escape.ps1

Param(
    [string]$StrExpFile,
    [string]$TargetWord,
    [string]$ReplaceWord
)

# $(Get-Content "$StrExpFile").replace($TargetWord,$ReplaceWord) | Set-Content -Encoding UTF8 "$StrExpFile"

如果没有特殊字符,set-content的默认编码与其相同。 - undefined
1个回答

8
在 PowerShell (Core) 7+ 中,默认情况下,你会得到无 BOM 的 UTF-8 文件;使用 -Encoding utf8 和 -Encoding utf8NoBom 可以明确表示默认值;要使用 BOM,需要使用 -Encoding utf8BOM。
在 Windows PowerShell 中,不幸的是,你必须使用一个解决方法来获取无 BOM 的 UTF-8,因为 -Encoding utf8 只会生成带有 BOM 的 UTF-8 文件(不支持其他 utf8 相关的值)。

这个解决方法需要将Out-StringNew-Item结合起来,即使在Windows PowerShell中,默认情况下它会创建无BOM的UTF-8文件。

Param(
    [string]$StrExpFile,
    [string]$TargetWord,
    [string]$ReplaceWord
)

$null = 
  New-Item -Force $StrExpFile -Value (
    (Get-Content $StrExpFile).Replace($TargetWord, $ReplaceWord) | Out-String
  )

注意:

  • $null = 需要丢弃New-Item生成的输出对象(它是描述新创建的文件的文件信息对象)。

  • -Force需要以静默方式覆盖同名的现有文件(与Set-ContentOut-File默认情况下相同)。

  • -Value参数必须是要写入文件的单个(多行)字符串,这就是Out-String确保的。

注意事项

对于非字符串输入对象,Out-String创建与Out-File相同的丰富的显示表示,并且默认情况下在控制台中看到的也是如此。
New-Item本身在将字符串写入文件时不会追加尾随换行符,但是Out-String却会;虽然这在这里很方便,但通常会引起问题,如GitHub问题#14444中所讨论的那样。
使用Out-String的替代方法是手动创建多行字符串,这有点麻烦(在Windows上,PowerShell和大多数程序都可以接受使用"`n"创建仅包含LF的换行符;对于平台本地的换行符(CRLF),请改用[Environment]::NewLine):
由于整个文件内容必须作为参数传递,因此它必须作为一个整体适应内存;下面讨论的便利函数避免了这个问题。
对于一个在Windows PowerShell中使用的方便的包装函数,用于创建无BOM的UTF-8文件,请参阅this answer

替代方案,使用.NET APIs 直接操作:

默认情况下,.NET APIs 生成无BOM的UTF-8文件。然而,因为.NET的工作目录通常与PowerShell的不同,在使用时必须始终使用完整文件路径,这需要更多的努力:

# In order for .NET API calls to work as expected,
# file paths must be expressed as *full, native* paths.
$OutDir = Split-Path -Parent $StrExpFile
if ($OutDir -eq '') { $OutDir = '.' }
$strExpFileFullPath = Join-Path (Convert-Path $OutDir) (Split-Path -Leaf $StrExpFile)

# Note: .NET APIs create BOM-less UTF-8 files *by default*
[IO.File]::WriteAllLines(
  $strExpFileFullPath,
  (Get-Content $StrExpFile).Replace($TargetWord, $ReplaceWord)
)

以上使用了System.IO.File.WriteAllLines方法。
请注意,虽然 New-Item 技术上支持通过 管道 接收要写入文件的内容,但不幸的是它会将每个值按顺序写入目标文件,只有最后一个值会出现在文件中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接