在PowerShell中如何转义引号

3
在 Powershell 中,我想运行以下命令:
bash -c "echo 'hello world!'"

(我知道可以直接使用echoWrite-Host,但我需要使用bash -c),并且我希望hello被单引号包围,world被双引号包围。换句话说,我想要以下输出:
'hello' "world"!

我应该如何转义这些引号?


但是你不是在运行PowerShell。你是在PowerShell会话中运行bash.exe。那不是同一件事。要在PowerShell中运行.exe,您必须正确配置该行。请参见此链接:--- https://social.technet.microsoft.com/wiki/contents/articles/7703.powershell-running-executables.aspx和这个---https://unix.stackexchange.com/questions/187651/how-to-echo-single-quote-when-using-single-quote-to-wrap-special-characters-in - postanote
2个回答

3

由于您正在调用程序(例如bash),因此转义引号字符的“普通”规则不一定以“相同”的方式工作。 PowerShell不会解释字符串(通常遵循“普通”引号规则),而是将参数传递给程序。这是以完全不同的方式解释的。

简而言之,要转义引号字符,需要使用以下命令:

bash -c "echo \'Hello\' \\\""World\\\""!"

输出:

'Hello' "World"!

现在看起来非常复杂。因此,让我们分解一下。
首先,在bash中输出所需引用的正确命令是什么?让我们尝试普通引号:
HAL9256@HAL9000:~$ echo 'Hello' "World"!
Hello World!

没有引号。哦,是的!我必须转义它们。在 bash 中,我必须用反斜杠(\)来转义它们:

HAL9256@HAL9000:~$ echo \'Hello\' \"World\"!
'Hello' "World"!

我们需要使用单个反斜杠来正确转义bash中的引号。因此,让我们将其插入到PowerShell中:

PS C:\> bash -c "echo \'Hello\' \"World\"!"
/bin/bash: -c: line 0: unexpected EOF while looking for matching `"'
/bin/bash: -c: line 1: syntax error: unexpected end of file

那不起作用。哦,对了,在PowerShell中,我们必须使用反引号(`)转义双引号,因为它们在一组双引号内:

PS C:\> bash -c "echo \'Hello\' \`"World\`"!"
'Hello' World!

好的,这没有出现错误,但仍然不是我们想要的。引号仍然没有被正确转义。烦死了。 这就是你开始打100种不同字符组合来找到正确组合的地方 ;-).

或者,让我们回到bash并找出可能发生的事情。首先,让我们记住正在echo的字符串被解释为字符串。因此,让我们在我们的echo语句周围放置双引号,以便它被视为字符串,并查看它的作用。请记住,我们希望从中得到的输出与早期的bash命令相同,具有反斜杠:

HAL9256@HAL9000:~$ echo "\'Hello\' \"World\"!"
\'Hello\' "World"!

最终,我们想要发送给 bash 的是带有反斜杠的原始字符串。在这里,我们可以看到反斜杠正在转义双引号并消失。因此,需要添加更多的反斜杠:

HAL9256@HAL9000:~$ echo "\'Hello\' \\"World\\"!"
\'Hello\' \World\!

哦,太好了。我们成功避开了反斜杠。就像电影《盗梦空间》一样,不断添加转义字符直到它能正常工作...

HAL9256@HAL9000:~$ echo "\'Hello\' \\\"World\\\"!"
\'Hello\' \"World\"!

好的,我们现在有了输出结果。现在我们需要将其输入到PowerShell中:

PS C:\> bash -c "echo \'Hello\' \\\"World\\\"!"
/bin/bash: -c: line 0: unexpected EOF while looking for matching `"'
/bin/bash: -c: line 1: syntax error: unexpected end of file

哦!是之前的同样错误。在PowerShell中,我们必须记得用反引号转义双引号:

PS C:\> bash -c "echo \'Hello\' \\\`"World\\\`"!"
'Hello' "World"!

成功了!只需要进行大量的转义,无论是在bash还是PowerShell中。另一种方法,我认为更易于理解的方式是在双引号内使用两个双引号来进行转义,而不是使用反引号,如下所示:

PS C:\> bash -c "echo \'Hello\' \\\""World\\\""!"
'Hello' "World"!

在我的电脑上,它不起作用,我没有得到任何引号。这是我的 $PSVersionTble:名称 值
PSVersion 7.0.0 PSEdition 核心 GitCommitId 7.0.0 OS Darwin 18.7.0 Darwin Kernel Version 18.7.0: Mon Feb 10 21:08:45 PST 2020; root:xnu… 平台 Unix PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…} PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1
- user3534974
很遗憾,什么都没有改变。 - user3534974
在下载和安装WSL后,我意识到我们不是在处理“典型”的PowerShell引号规则。我们还要处理参数的解析和解释。这意味着你必须对转义有点疯狂。请参见上面的编辑。 - HAL9256
好的...我想我明白了。没有一种独特的转义引号的方式:事实上,如果我们将整个bash命令放在单引号中(而不是双引号),我们不能使用完全相同的引号。我的问题是,我试图制作一个自动转义引号的函数,但仅向其传递字符串是不够的...我还必须告诉它转义后的字符串是否将被包含在单引号或双引号中。它可以工作,但并不像我想象的那么简单 :) - user3534974

2

HAL9256的答案很有帮助,但是让我试着用不同的方式来表述这个问题:

如果你从bash本身运行命令,为了获得所需的逐字输出,你的命令应该像这样:

# From Bash itself
$ bash -c "echo \"'hello' \\\"world\\\"!\""
'hello' "world"!

Bash对上述字符串字面量的初始解析,其中\作为转义字符,意味着新的bash实例将以下文本作为其-c参数:
echo "'hello' \"world\"!"
因此,如果您直接在Bash中执行此命令,它也会产生所需的输出。
请注意,echo参数作为整体被包含在(最初\转义的)"..."中,以确保鲁棒性:如果worldworld & space,则命令会中断; 同样,world class将变成world class(由于shell扩展而进行的空格规范化)。
需要许多\字符,因为涉及到2层转义:

  • 为了调用shell(在本例中也是bash),以确保输入字符串在语法上有效:\"嵌入一个单个的",而\\是单个的\

  • 针对目标shell(bash),以便结果字符串在语法上对于是有效的,考虑到在这种情况下将解析为命令的结果字符串。

翻译该命令以便可以从PowerShell中调用需要调整上述第一层,这意味着使用`,PowerShell的转义字符,而不是\
因此,直接翻译如下:
# SHOULD work, but DOESN'T as of PowerShell 7.0
PS> bash -c "echo `"'hello' \`"world\`"!`""
hello          # !! WRONG output.

如果您直接在PowerShell中打印字符串文字"echo `"'hello' \`"world\`"!`"",则会发现它会正确地生成verbatim字符串,就像上面展示的那样(echo "'hello' \"world\"!")。但是,这种方法不起作用的原因在于 PowerShell将参数传递给外部程序时,始终存在问题,特别是在处理嵌入式双引号这个答案提供了一个概述,但简单来说,截至PowerShell 7.0:除了满足PowerShell的自己的语法要求(如果您调用PowerShell命令,则足够),您必须额外\转义嵌入式"字符,以便传递给外部程序的参数。因此:
# OK, but the manual \-escaping shouldn't be necessary.
PS> bash -c "echo \`"'hello' \\\`"world\\\`"!\`""
'hello' "world"!

为什么当前的行为是错误的:
一个 shell 的工作是将其自身解析得到的参数原封不动地传递给目标程序,同时在幕后进行必要的操作以确保这一点 - 除了 PowerShell 自己的转义要求之外,您不需要担心任何转义要求:
- 在 Windows 上,出于不幸的必要性,这意味着在幕后构建一个命令行,根据需要应用双引号和转义;虽然 PowerShell 根据需要应用双引号,但缺少的是嵌入参数中的“”字符的 \ 转义。 - 在类 Unix 平台上,不需要额外的努力:在那里,程序直接接收参数作为纯文本值的数组。
虽然本问题中讨论的特定命令使得翻译到 PowerShell 相当简单,但有更加隐蔽的情况,需要额外的 \ 转义 - 这总是很麻烦的,并且意外的是,因为这些命令在 bash 中可以正常工作。
PS> bash -c 'echo "hi, there"'
hi,   # !! " were stripped, so bash only saw `echo hi,` as the command string,
      # !! and `there` as a separate argument.

PS> /bin/echo '{ "foo": "bar" }' # Try to pass a JSON string
{ foo: bar } # !! BROKEN JSON

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