为什么 Windows 上的 curl 命令会生成 /bin/bash: 行 /: $'\r' : 找不到命令错误?



我正试图从官方文档中安装Operator Lifecycle Manager(OLM),这是一种帮助管理集群上运行的Operators的工具,但我一直收到下面的错误。可能出了什么问题?

这是命令的结果:

curl -sL https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.22.0/install.sh | bash -s v0.22.0
/bin/bash: line 2: $'r': command not found
/bin/bash: line 3: $'r': command not found
/bin/bash: line 5: $'r': command not found
: invalid option6: set: -
set: usage: set [-abefhkmnptuvxBCEHPT] [-o option-name] [--] [-] [arg ...]
/bin/bash: line 7: $'r': command not found
/bin/bash: line 9: $'r': command not found
/bin/bash: line 60: syntax error: unexpected end of file

我已经尝试删除现有的curl,并下载并安装了另一个版本,但问题仍然存在。大多数在线解决方案都是为Linux用户提供的,它们都会导致Windows路径设置和文件问题。

我还没有找到一个解决使用curl安装文件的问题。

我很乐意接受任何帮助。

在Windows上使用PowerShell时,当PowerShell将curl.exe发出的stdout行传递给bash时,必须明确确保它们与Unix格式的CRLF换行符n分隔,因为bash和其他Unix shell一样,无法识别Windows格式的CRLFnewlinesrn:

避免问题的最简单方法是通过cmd /c调用:

cmd /c 'curl -sL https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.22.0/install.sh | bash -s v0.22.0'

与PowerShell(见下文)不同,cmd.exe的管道(|)(以及其重定向运算符>)充当原始字节管道,因此它只是将curl.exe输出的任何字节流式传输到接收bash调用,而不做更改。

修复PowerShell侧的问题需要更多的工作,并且天生就较慢

(
(
curl -sL https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.22.0/install.sh 
) -join "`n"
) + "`n" | bash -s v0.22.0

注意:`n是一个PowerShell转义序列,它生成一个文本LF字符,类似于某些bash上下文中的n

注:

  • 需要注意的是,从PowerShell 7.2.x开始,不支持通过管道传递原始字节:外部程序stdout输出在读取时总是被解码为.NET字符串,并且当写入(其他)外部程序时,基于$OutputEncoding首选变量重新编码

    • 有关更多信息,请参阅此答案,以及GitHub 1908号问题,了解未来对外部程序之间的原始字节流和重定向到文件的潜在支持
  • 也就是说,PowerShell总是将来自外部程序(如curl.exe)的输出解释为文本,并通过管道逐行发送作为.NET字符串对象(PowerShell管道通常执行(.NET)对象)。

    请注意,这些行(字符串)本身没有换行符;也就是说,关于最初将行分隔开的特定换行序列的信息在该点上丢失了(PowerShell本身可互换地识别CRLF和LF换行)
  • 但是,如果接收命令是也是外部程序,则PowerShell会在每行中添加一个尾随平台本机换行符,在Windows上是CRLF换行符-这就是问题的原因。

  • 通过使用(...)在前面收集阵列中的行,可以使用-join运算符将它们作为单个LF分隔的多行字符串发送,如上所示。

    • 请注意,PowerShell也会将一个尾随的平台本机换行符附加到这个单行多行字符串中,但bash实际上会忽略输入的最末尾处的杂散rn,假设最后一个真正的输入行以n结尾,这就是表达式末尾额外的+ "`n"所确保的。

    • 然而,在某些情况下,这个尾随的CRLF换行符确实会导致问题——请参阅此答案,以获取通过平台本机shell的示例和解决方案。

  • 首先,我需要清楚一些事情:

    1. 根据问题的标签,我看到我们在PowerShell中,而不是linux/unix,甚至是Windows cmd shell
    2. 尽管如此,我们使用的是Unixcurl(可能是curl.exe),而不是Invoke-WebRequest的PowerShell别名。我们之所以知道这一点,是因为-sL的论点。如果Powershell使用别名,我们会看到完全不同的错误

    接下来,我需要简要谈谈行尾。Windows默认情况下使用两个字符的LF/CR对(nr)作为行尾,而不是Unix/linux中和bash所期望的单个LF(n)字符。


    有了这些背景,我现在可以解释问题的原因了。这是一个单管字符:

    | 
    

    这是PowerShell管道,而不是Unix管道,因此该操作将curl程序的输出放在PowerShell管道中,以便将其发送到bash解释器。每一行都是管道上的一个单独项目,因此不再包括任何原始换行符。PowerShell管道将";正确的";这是在使用系统的默认行结尾调用bash之前,在本例中是Windows使用的LF/CR对。现在,当bash试图解释输入时,它在每行后面都会看到一个额外的r字符,不知道该怎么处理

    关键是,我们在Powershell中可能会做的去除多余字符的大部分操作,在完成后仍将通过另一个管道发送。我想我们可以告诉curl在不使用管道的情况下将文件写入磁盘,然后告诉bash运行保存的文件,但这很尴尬,需要额外的工作,而且速度要慢得多。


    但我们可以做得更好。PowerShell默认情况下将curl返回的每一行视为管道上的一个单独项目。我们可以";技巧";而是使用CCD_ 33操作将一个大项目放在流水线上。这将为我们提供一个可以作为单个元素在管道上运行的大字符串。它最终仍然会有一个额外的r字符,但当bash看到它时,脚本已经完成了它的工作。

    实现这一点的代码可以在另一个答案中找到,他们应该为解决方案获得所有赞誉。我写这篇文章的目的是更好地解释发生了什么:为什么我们有问题,为什么解决方案有效,因为我必须通读几遍才能真正得到答案。

    最新更新