【问题标题】:Script in powershell not working with array variablespowershell中的脚本不能使用数组变量
【发布时间】:2022-07-28 02:43:00
【问题描述】:

我创建一个 PowerShell 脚本只是为了备份我的 WSL 发行版,但是当我尝试使用变量运行命令时它不起作用,它会显示使用文本,就好像我提供了不正确的参数一样。

$DistrosArray1 =  (wsl -l --quiet) | where {$_ -ne ""}
$DistrosArray2 = 'Arch', 'Ubuntu-22.04', 'docker-desktop-data', 'docker-desktop'

$CheckArrayDifference = Compare-Object -ReferenceObject $DistrosArray1 -DifferenceObject $DistrosArray2 -PassThru
echo $CheckArrayDifference

# Does not return anything (there is no difference)

foreach ($Distro in $DistrosArray1) {
    wsl --export $Distro "$Distro.tar"
    # This method is not working
  }

foreach ($Distro in $DistrosArray2) {
    wsl --export $Distro "$Distro.tar"
    # This method is working
  }

【问题讨论】:

    标签: powershell windows-subsystem-for-linux


    【解决方案1】:

    听起来您遇到了问题 #4607 带来的麻烦——wsl.exe 命令输出一些奇怪的 UTF16 编码,当尝试从 PowerShell(甚至从 WSL 内部)处理它时会产生问题。

    此问题现已在最新的 WSL 预览版 0.64.0 中得到修复,但您必须“选择加入”修复程序,以便旧的解决方法(如 @Bender 和我提供的解决方法)不会无意中中断。

    简单设置:

    $env:WSL_UTF8=1
    

    ...在您的代码之前,WSL 将不再吐出“损坏的 UTF16”。

    我的回答中的其他示例:

    旧的解决方案:

    让我们简化问题,做一个不尝试导出的“安全”示例:

    $DistrosArray1 =  (wsl -l --quiet) | where {$_ -ne ""}
    wsl -d $DistrosArray1[0]
    

    结果:

    There is no distribution with the supplied name.
    

    我已经成功使用this comment中的方法处理了。对于这个特定的例子:

    $console = ([console]::OutputEncoding)
    [console]::OutputEncoding = New-Object System.Text.UnicodeEncoding
    $DistrosArray1 =  (wsl -l --quiet) | where {$_ -ne ""}
    wsl -d $DistrosArray1[0]
    

    这将正确运行列表中的第一个分发。

    使用以下代码重置编码:

    [console]::OutputEncoding = $console
    

    这对于大多数非交互式脚本来说应该不是问题,因为它只是“包装器”的最后一行,但正如 @BendertheGreatest 在 cmets 中指出的那样,这是一个关键 步骤。

    【讨论】:

    • 很好地找到了该解决方法 :) PSA 面向所有读者; 按照建议更改控制台编码尤为重要。特别是在您显示其他内容或开始处理其他字符串之前。
    • 呵呵明白了。我使用这种方法遇到了这个错误“安装一个文件系统时出错。运行'dmesg'以获取更多详细信息”。我已经从数组中排除了 docker-desktop 和 docker-desktop-data。
    • @AntonioCosta Hmm - 排除了docker-desktopdocker-desktop-data,我们需要找出哪个实例有问题,所以我建议在循环中放置echo $Distro 来确定。
    • 我找到了有问题的发行版。实际上,我只是在使用 Ubuntu-22.04 和 Arch。 Arch Linux 就是有问题的那个。当我写“Arch”字符串正常工作。
    • @AntonioCosta 只是为了确保我理解——foreach 循环中的“Arch”会给出错误,但将其作为硬编码字符串运行是否可以?我的解决方法和 Bender 的解决方法都会发生这种情况?
    【解决方案2】:

    This is part of a known issue with wsl.exe output。以下是我针对该问题提供的解决方法汇总的内容:

    $DistrosArray1 = wsl -l --quiet | wsl iconv -c -f utf16 -t ascii
    
    foreach ($Distro in $DistrosArray1) {
      wsl --export $Distro "$Distro.tar"
    }
    

    不幸的是,我无法通过转换为 UTF8 来实现这一点(将 ascii 更改为 utf8 会产生额外的垃圾字符,尽管它们在我有限的测试中是一致且可检测的),因此只有 ASCII 范围之外的任何字符才会可能会给您带来麻烦。

    【讨论】:

    • -t UTF8 怎么样?这就是我通常在inside WSL 中使用的,至少。如果这在 PowerShell 中不起作用,但我的猜测是我们会看到在通过外部命令进行管道传输时添加回车的“正常”PowerShell 副作用。
    • @NotTheDr01ds 我已经介绍过这个案例。我已经尝试过使用-f utf16 以及LE 和BE 变体,并尝试将所有这些尝试转换为-t ascii-t utf8。我发现导致预期输出的唯一混合是-f utf16 -t ascii-f utf16le -t ascii(Windows 上的UTF-16 无论如何都默认为小端,所以这两种工作都不足为奇)
    • 糟糕——错过了。其实,误读了。
    • 哦,知道了。我尝试运行这些命令,这是出现的消息:“安装文件系统之一时出错。运行 'dmesg' 以获取更多详细信息。”
    • @AntonioCosta 这可能是docker-desktop 和/或docker-desktop-data 图像。我建议跳过这些。尝试添加类似$DistrosExcluded = "docker-desktop-data","docker-desktop"; $DistrosArray1 = $DistrosArray1 | ? {$_ -notin $DistrosExcluded }
    猜你喜欢
    • 2021-01-30
    • 1970-01-01
    • 2021-09-07
    • 1970-01-01
    • 1970-01-01
    • 2014-09-10
    • 1970-01-01
    • 2013-12-01
    • 2014-08-09
    相关资源
    最近更新 更多