传递带空格的参数给Start-Process

huangapple go评论50阅读模式
英文:

Pass Arguments to Start-Process with spaces

问题

以下是翻译好的部分:

我想将PowerShell参数传递给一个进程。这些参数可能包含空格。

Powershell 代码:

$proc = Start-Process -FilePath "wsl.exe" -ArgumentList $args -NoNewWindow -PassThru
$proc | Wait-Process

运行命令:

powershell -noprofile -executionpolicy bypass -file sh.ps1 bash -c "`"echo Hello World`""

没有输出。


使用静态数组运行此命令可以正常工作:

$proc = Start-Process -FilePath "wsl.exe" -ArgumentList @("bash", "-c", "`"echo Hello World`"") -NoNewWindow -PassThru
$proc | Wait-Process

输出:

Hello World

我需要做什么来从CLI参数中转义这些参数?

请参阅 https://github.com/PowerShell/PowerShell/issues/5576 了解为什么我必须转义空格。

英文:

I would like to pass the powershell arguments to an process. The arguments may contain spaces.

Powershell Code:

$proc = Start-Process -FilePath "wsl.exe" -ArgumentList $args -NoNewWindow -PassThru
$proc | Wait-Process

Run Command

powershell -noprofile -executionpolicy bypass -file sh.ps1 bash -c "`"echo Hello World`""

No Output.


Running this command with static array works fine:

$proc = Start-Process -FilePath "wsl.exe" -ArgumentList @("bash", "-c", "`"echo Hello World`"") -NoNewWindow -PassThru
$proc | Wait-Process

Output

Hello World

What I needed todo to escape the arguments from the CLI args?

See https://github.com/PowerShell/PowerShell/issues/5576 why I have to escape spaces

答案1

得分: 1

以下是已翻译的部分:

"Start-Process"在您的情况下没有充分的理由使用(请参阅此GitHub文档问题以获取有关何时适用于"Start-Process"的指导)。

相反,使用_直接执行_,这不仅是同步的,并且在同一个控制台窗口中运行(对于像"wsl.exe"这样的_控制台_应用程序),还允许您直接捕获或重定向输出。

通过这样做,您还将绕过您提到的长期存在的"Start-Process"错误(GitHub问题#5576),因为PowerShell会在幕后_根据需要_对传递给外部程序的参数进行双引号处理(特别是如果它们包含空格)。

$exe, $exeArgs = $args   # 将参数数组拆分为可执行文件和传递的参数
wsl.exe -e $exe $exeArgs # 同步执行,通过wsl -e

请注意,您此时也不需要在PowerShell CLI调用中嵌入转义的"

powershell -noprofile -executionpolicy bypass -file sh.ps1 bash -c "echo Hello World"

但是,如果您的参数确实需要嵌入的",则会遇到另一个长期存在的仅影响_直接_调用外部程序的PowerShell错误,需要使用\进行_手动_转义 - 请参阅此答案。

如果您需要使用"Start-Process" - 例如,如果您希望进程在_新的(控制台)窗口_中运行 - 您将不得不为那些需要的$args元素提供_嵌入的_引号,如下所示:

$quotedArgs = foreach ($arg in $args) {
  if ($arg -notmatch '[ "]') { $arg }
  else { # 必须双引号
    '"{0}"' -f ($arg -replace '"', '\"' -replace '\$', '\\')
  }
}

$proc = Start-Process -FilePath "wsl.exe" -ArgumentList $quotedArgs -PassThru
$proc | Wait-Process
英文:

<!-- language-all: sh -->

There's no good reason to use Start-Process in your case (see this GitHub docs issue for guidance on when Start-Process is and isn't appropriate).

Instead, use direct execution, which is not only synchronous and runs in the same console window (for console applications such as wsl.exe), but also allows you to directly capture or redirect output.

In doing so, you'll also be bypassing the longstanding Start-Process bug you mention (GitHub issue #5576), because PowerShell double-quotes arguments passed to external programs as needed behind the scenes (namely if they contain spaces).

$exe, $exeArgs = $args   # split argument array into exe and pass-thru args
wsl.exe -e $exe $exeArgs # execute synchronously, via wsl -e 

Note that you then also don't need to embed escaped &quot; in your PowerShell CLI call:

powershell -noprofile -executionpolicy bypass -file sh.ps1 bash -c &quot;echo Hello World&quot;

However, if your arguments truly needed embedded &quot;, you'd run into another longstanding PowerShell bug that affects only direct invocation of external programs, necessitating manual escaping with \ - see this answer.


If you do need to use Start-Process - e.g. if you want the process to run in a new (console) window - you'll have to provide embedded quoting around those $args elements that need it, along the following lines:

$quotedArgs = foreach ($arg in $args) {
  if ($arg -notmatch &#39;[ &quot;]&#39;) { $arg }
  else { # must double-quote
    &#39;&quot;{0}&quot;&#39; -f ($arg -replace &#39;&quot;&#39;, &#39;\&quot;&#39; -replace &#39;\$&#39;, &#39;\\&#39;)
  }
}

$proc = Start-Process -FilePath &quot;wsl.exe&quot; -ArgumentList $quotedArgs -PassThru
$proc | Wait-Process


</details>



# 答案2
**得分**: 0

显而易见的答案是,使用`$myargs`作为字符串数组。 "echo Hello World" 需要嵌入的双引号(或单引号)来包裹它,这会使事情变得复杂。

```powershell
$myargs = "bash", "-c", "'echo Hello World'"
$proc = Start-Process -FilePath wsl.exe -ArgumentList $myargs -NoNewWindow -PassThru
$proc | Wait-Process

Hello World

我会这样做:

.\sh.ps1 bash -c 'echo hello world'

# sh.ps1 包含:
# wsl $args

或者对于 Windows 上的 WSL bash:

bash -c 'echo hello world'

我碰巧在 WSL 中安装了 pwsh。没有单引号,每个单词将被放在新行上。

wsl pwsh -c "echo 'hello world'"

这对我来说在另一个 PowerShell 中也有效,其中有另一组嵌入的引号:

powershell -noprofile -executionpolicy bypass -file sh.ps1 bash -c "`'echo Hello World`'"
英文:

The obvious answer is this, with $myargs being an array of strings. "echo Hello World" needs embedded double-quotes (or single-quotes) around it, which complicates things.

$myargs = &quot;bash&quot;, &quot;-c&quot;, &quot;&#39;echo Hello World&#39;&quot;
$proc = Start-Process -FilePath wsl.exe -ArgumentList $myargs -NoNewWindow -PassThru
$proc | Wait-Process

Hello World

I would just do:

.\sh.ps1 bash -c &#39;echo hello world&#39;

# sh.ps1 contains:
# wsl $args

Or the wsl bash for windows:

bash -c &#39;echo hello world&#39;

I happened to have pwsh installed within wsl. Without the single-quotes, each word would be put on a new line.

wsl pwsh -c &quot;echo &#39;hello world&#39;&quot;

This works for me within another powershell, with yet another set of embedded quotes:

powershell -noprofile -executionpolicy bypass -file sh.ps1 bash -c &quot;`&quot;&#39;echo Hello World&#39;`&quot;&quot;

huangapple
  • 本文由 发表于 2023年1月8日 22:28:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/75048543.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定