【问题标题】:How to create VSCode task creating a file without BOM如何创建没有 BOM 的文件的 VSCode 任务
【发布时间】:2019-12-17 16:22:18
【问题描述】:

在启动 Angular e2e 测试时,我需要根据 gopass 密钥创建一个 JSON 文件。不幸的是,我将 JSON 编码为带有 BOM 的 UTF-8。

我在由启动配置之一启动的tasks.json中创建了任务,尝试配置它但没有成功。问题是由 PowerShell 引起的,它默认使用 BOM 字符写入文件。 我试图将任务类型更改为进程(也使用密钥和输出文件作为参数运行),但后来我遇到了没有选择正确的 gopass 密钥或运行命令的问题。 我无法对我的测试代码进行细微的更改,所以我需要通过 tasks.json/launch.json 进行设置。

我目前的任务配置:

{
    "type": "shell",
    "label": "Get data",
    "command": "gopass \"somekey\" > \"myFile.json\""
},

我想获取没有 BOM 字符的 JSON 文件

【问题讨论】:

  • 顺便说一句:Windows PowerShell 中的> 不只是创建 BOM,它使用 UTF-16LE 编码(“Un​​icode”),而不是 UTF-8。
  • @mklement0 谢谢,但我认为,没有比您建议的更简单的解决方案了,或者有什么方法可以摆脱 > 以支持其他方法吗?
  • 这些是基本选择:(a) 使用 PowerShell Core,如我的回答(这对您来说还不够简单)。 (b)修改您的命令以直接使用 .NET 来编写文件,如 Theo 的答案所示,现在也在我的顶部的上下文中。 (c) 如果您知道您的数据从不包含非ASCII范围的字符,您可以使用Set-Content,如js2010的回答:使用@987654325 @ 而不是 > \"myFile.json\"

标签: json powershell visual-studio-code byte-order-mark


【解决方案1】:

据我了解,从 PowerShell 版本 6 开始,Set-ContentOut-File 都支持 UTF8NoBOM 编码。

如果您的版本低于 6.0,您可以使用以下任一代码将 json 字符串保存为不带 BOM 的 UTF8:

$json = @"
{
    "type": "shell",
    "label": "Get data",
    "command": "gopass \"somekey\" > \"myFile.json\""
}
"@

使用UTF8Encoding 对象并将encoderShouldEmitUTF8Identifier 参数设置为$false

$Utf8NoBom = New-Object System.Text.UTF8Encoding $false
[System.IO.File]::WriteAllText('D:\launch.json', $json, $Utf8NoBom)

使用StreamWriter 对象,默认输出不带BOM 的UTF8

$sw = New-Object System.IO.StreamWriter 'D:\launch.json'
$json | Out-String -Stream | ForEach-Object { $sw.Write($_) }
$sw.Dispose()

【讨论】:

  • 这通常很有帮助,但请注意,问题中的 JSON 本身并不是要写入文件的;它是一个 Visual Studio Code 任务定义,包含一个 PowerShell 命令行,由 Visual Studio Code 通过其默认 shell(即 Windows PowerShell)执行。 OP 希望将命令嵌入到任务中,gopass "somekey" > "myFile.json",生成无 BOM 的 UTF-8。
  • 忘了提到 System.IO.File 方法也默认为无 BOM 的 UTF-8,因此您的第一个命令可以简化为:[IO.File]::WriteAllText('D:\launch.json', $json) - 无需构造和传递编码对象。
【解决方案2】:

如果你使用 set-content,就不会有 bom。 PS 5 中的默认值为“ansi”。

或者你说的是 vscode 本身?保存的默认编码是utf8 no bom。

【讨论】:

  • 虽然这个问题有点模棱两可,但可以公平地假设需要无 BOM 的 UTF-8,因为在没有 BOM 的情况下,这是 JSON 的默认编码: “JSON 文本应以 Unicode 编码。默认编码为 UTF-8。”(来自RFC 4627 的第 3 节)。现在,如果输入文本恰好仅包含 7 位 ASCII 范围内的字符,您可以使用活动的 ANSI 编码(甚至 -Encoding ASCII侥幸逃脱,但应明确说明该假设.
  • 我不确定我是否理解正确,但通常我希望以正确的 json 格式获得任务“获取数据”的结果,以便进一步使用操作。
  • 我正在使用"gopass \"somekey\" > \"myFile.json\"",但@mklement0 解决方案对我有用。
【解决方案3】:

Theo's answer 向您展示了如何在 Windows 上制作 Visual Studio Code 的默认 shell,Windows PowerShell,创建 BOM-les 的 UTF-8 文件,不幸的是,非常麻烦,因为标准运算符和 cmdlet 不支持它。

在您的情况下,最短的公式是替换:

"command": "gopass \"somekey\" > \"myFile.json\""

与:

"command": "[IO.File]::WriteAllLines(\"$pwd\myFile.json\", (gopass \"somekey\"))"

为了方便将 tasks.json 任务定义为可以使用 > 的未修改 PowerShell 命令字符串,同时还可以生成无 BOM 的 UTF-8 输出,您可以制作您的任务使用 PowerShell Core (v6+) 作为 shell,因为 PowerShell Core 的文件输出 cmdlet 和操作符始终默认为无 BOM 的 UTF8

先决条件:确保已安装PowerShell Core
底部展示了如何执行自动按需安装

注意:最终,PowerShell Core 将与旧版 Windows PowerShell 版本一起预装在 Windows 上,但这 (a) 暂时不会发生,并且 ( b) 没有具体的时间框架。


  • 如果您可以全局将 PowerShell Core 替换为 Windows PowerShell - 则无需更改您的任务定义:

注意:这意味着 集成终端 以及 tasks.json 中的所有 "shell" 类型任务将使用 PowerShell Core

打开setting.json(从命令面板中选择> Preferences: Open Settings (JSON))并添加以下属性:

    "terminal.integrated.shell.windows": "pwsh.exe"

注意:如果pwsh.exe 不在您系统的PATH 中,请在"executable" 属性中指定完整 路径;您可以通过打开 PowerShell Core 窗口并执行 (Get-Process -Id $PID).Path 来获取它。


  • 如果您想用 PowerShell Core 替换 Windows PowerShell单独任务

"option" 对象添加到您的任务定义 JSON 中,使其使用 PowerShell Core 的 CLI 而不是 Windows PowerShell 的:

{
    "type": "shell",
    "label": "Get data",
    "command": "gopass \"somekey\" > \"myFile.json\""
    "options": {
      "shell": {
         "executable": "pwsh.exe",
         "args": [ "-noprofile", "-command" ]
      }
    }
}

在 Windows 上使用自动按需安装 PowerShell Core:

由于执行 PowerShell Core 的自动化用户级安装很容易,您可以完全自动化整个过程,如下所示:

  • 定义一个新的EnsurePsCoreInstalled 任务,检查是否存在 PowerShell Core,并在需要时安装它。

    • 它将被安装到$env:LOCALAPPDATA\powershell
    • 当然,当按需安装发生时(每台机器一次),会有明显的延迟。
    • 重要提示:一次性安装后Visual Studio Code 不会立即找到pwsh.exe,因此您需要:
      • 从 Windows 注销并重新打开(或重新启动),然后重新启动 Visual Studio Code
      • 退出 Visual Studio Code,打开一个 PowerShell 窗口并从那里重新启动它(只需运行code)。
      • 这个要求很不幸,但是 v1.37 版本的 Visual Studio Code 不支持会话中的环境更改;如果您希望看到这种变化,请投票给feature request on GitHub
{
    "label": "EnsurePsCoreInstalled",
    "type": "process",
    "command": "powershell.exe",
    "args": [
        "-noprofile",
        "-command",
        "if (gcm -ea ignore pwsh) { exit 0 }; Write-Verbose -vb 'Installing PowerShell Core...'; iex \"& { $(irm https://aka.ms/install-powershell.ps1) }\"; $dir = $env:LocalAppData + '\\Microsoft\\PowerShell'; $userPath = [Environment]::GetEnvironmentVariable('Path', 'User') -split ';' -ne ''; if ($dir -notin $userPath) { [Environment]::SetEnvironmentVariable('Path', ($userPath + $dir) -join ';', 'User') }; $env:Path += ';' + $dir; if (gcm -ea ignore pwsh) { Throw 'PowerShell Core was just installed on demand. To make it usable, log off and on again or reboot, or restart Visual Studio Code from a new PowerShell window (run `code`).' } else { Throw 'Installation of PowerShell Core FAILED.' }"
    ],
    "problemMatcher": []
}
  • 要让您的Get Data 任务首先执行任务EnsurePsCoreInstalled,添加以下属性:
    • "dependsOn": "EnsurePsCoreInstalled"
    • 注意:这样做会减慢您的任务,因为任务EnsurePsCoreInstalled 将首先被调用每次。如果它发现已安装 PowerShell Core 会迅速返回,但运行该任务的 Windows PowerShell 本身具有显着的启动成本。

【讨论】:

    猜你喜欢
    • 2011-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-01
    • 2020-11-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多