简体   繁体   English

Windows 版 Git 中的 Bash:使用 CMD.exe /C 和 args 运行命令时很奇怪

[英]Bash in Git for Windows: Weirdness when running a command with CMD.exe /C with args

This is more of an annoyance rather than a problem but I would very much like to understand the semantics here.这更像是一个烦恼而不是一个问题,但我非常想了解这里的语义。

All I want to do is to run an arbitrary command on a temporary command-prompt session which itself running under a bash session.我想要做的就是在临时命令提示符会话上运行任意命令,该会话本身在 bash 会话下运行。

My success rate is 50/50 as some command works as expected whereas others not so much.我的成功率为 50/50,因为某些命令按预期工作,而其他命令则不然。

I think the problem may lie around arguments not lining up properly (ie missing or merged arguments)我认为问题可能在于参数没有正确排列(即缺少或合并的参数)

I'll try to explain what I mean by weird by a series of commands and responses.我将尝试通过一系列命令和响应来解释我所说的奇怪是什么意思。 (I'm trying to get the word test to be printed on the screen.) (我正在尝试将单词test打印在屏幕上。)

I'm running these under GNU bash, version 3.1.0(1)-release (i686-pc-msys) Bundled with Git-1.8.4:我在与 Git-1.8.4 捆绑的GNU bash 版本 3.1.0(1)-release (i686-pc-msys)下运行这些:

First attempt:第一次尝试:

$ cmd /c echo test
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.
c:\>

Second attempt:第二次尝试:

$ cmd '/c echo test'
test"

Third attempt:第三次尝试:

$ cmd "/c echo test"
test"

Fourth attempt:第四次尝试:

$ cmd /c\ echo\ test
test"

Fifth attempt:第五次尝试:

$ cmd "/c echo" test
'echo" test' is not recognized as an internal or external command,
operable program or batch file.

I'd really appreciate any pointers or insights into the behaviors above as this is unintuitional to me and driving me crazy!我真的很感激对上述行为的任何指示或见解,因为这对我来说是不直观的,让我发疯!

Edit: There is another question that appears similar to this, but it really isn't, mainly because it's about running batch files through CMD /C that doesn't require any arguments.编辑:还有另一个问题与此类似,但实际上并非如此,主要是因为它是关于通过不需要任何参数的 CMD /C 运行批处理文件。

It doesn't really answer my question about how to provide arguments properly to windows command line apps, and even though the examples are about CMD /C, the answer here can be applied to many other Windows command line apps as well.它并没有真正回答我关于如何为 Windows 命令行应用程序正确提供参数的问题,即使示例是关于 CMD / C 的,这里的答案也可以应用于许多其他 Windows 命令行应用程序。

This is actually documented in the ReleaseNotes file (in the top level folder of your installed Git for Windows)这实际上记录在 ReleaseNotes 文件中(在您安装的 Git for Windows 的顶级文件夹中)

Also, extra care has to be paid to pass Windows programs Windows paths, as they have no clue about MSys style POSIX paths -- You can use something like $(cmd //c echo "$POSIXPATH").此外,必须特别注意传递 Windows 程序 Windows 路径,因为它们不知道 MSys 风格的 POSIX 路径——您可以使用类似 $(cmd //c echo "$POSIXPATH") 的东西。

If you use cmd //c echo test it works as expected.如果您使用cmd //c echo test它会按预期工作。

$ cmd //c echo test
test

The cause is to do with trying to ensure that posix paths end up being passed to the git utilities properly.原因是试图确保 posix 路径最终正确传递给 git 实用程序。 For this reason, Git for Windows includes a modified MSYS layer that affects command arguments.出于这个原因,Git for Windows 包括一个影响命令参数的修改后的 MSYS 层。 You should note that it is not intended that the bash shell and tools provided with Git for Windows be used as general purpose unix tools for Windows.您应该注意,Git for Windows 提供的 bash shell 和工具并不打算用作 Windows 的通用 unix 工具。 If you want a general purpose unix-style toolset then you should install MSYS or cygwin.如果你想要一个通用的 unix 风格的工具集,那么你应该安装 MSYS 或 cygwin。 The Git Bash shell is setup for working with git and sometimes that shows. Git Bash shell 是为使用 git 设置的,有时会显示。

After reading this article I've found solution which works for me:阅读这篇文章后,我找到了对我有用的解决方案:

$ cat gvim.sh
cmd << EOD
gvim $@
EOD
$

Windows 8.1, Git (version 1.9.5-preview20141217), GNU bash, version 3.1.20(4)-release (i686-pc-msys). Windows 8.1、Git(版本 1.9.5-preview20141217)、GNU bash,版本 3.1.20(4)-release (i686-pc-msys)。

I am able to mostly reproduce the problem using gnu bash for Windows.我能够在 Windows 上使用 gnu bash 来重现问题。

I can't quite establish a pattern with the first form without any quotes.我不能完全建立一个没有任何引号的第一种形式的模式。 It seems to work with the Windows ECHO command, but not with other commands like DIR.它似乎适用于 Windows ECHO 命令,但不适用于 DIR 等其他命令。 EDIT - It turns out gnu bash is putting quotes around my command, so echo test becomes "echo" "test" .编辑- 结果是 gnu bash 在我的命令周围加上引号,所以echo test变成了"echo" "test" The quotes cause cmd.exe to look for an external command instead of the internal ECHO command.引号导致 cmd.exe 查找外部命令而不是内部 ECHO 命令。 I happen to have "echo.exe", so it appears to run.我碰巧有“echo.exe”,所以它似乎可以运行。 The odd thing is the quotes around test are not displayed.奇怪的是 test 周围的引号没有显示。 When I attempt to run the DIR command, it fails entirely because there isn't any DIR.EXE.当我尝试运行 DIR 命令时,它完全失败,因为没有任何 DIR.EXE。

The subsequent forms with quotes (except the last one), or escaped spaces, work the same as you are seeing - there is an unwanted trailing quote in the command.带有引号的后续形式(最后一个除外)或转义空格的工作方式与您所看到的相同 - 命令中有一个不需要的尾随引号。

I could not come up with a clean solution.我想不出一个干净的解决方案。 However, I have an ugly hack that should give you the desired result.但是,我有一个丑陋的 hack 应该可以给你想要的结果。 Simply concatenate a REM command at the end of your command.只需在命令末尾连接一个 REM 命令。 The REM will comment out the unwanted trailing quote. REM 将注释掉不需要的尾随引用。 It is important that there be a space after REM, otherwise REM" will not be recognized as a valid command. Any of the following should work. REM 后面有一个空格很重要,否则REM"将不会被识别为有效命令。以下任何一种都应该有效。

$ cmd '/c echo test&rem '
$ cmd "/c echo test&rem "
$ cmd /c\ echo\ test\&rem\ 

Note that the last command has a space after the backslash.请注意,最后一个命令在反斜杠后有一个空格。

The technique should work for pretty much any command string that you might want to execute via CMD.EXE.该技术几乎适用于您可能希望通过 CMD.EXE 执行的任何命令字符串。

As I explain here , there is an additional alternative when using modern Git for Windows' bash正如我在此处解释的那样,在将现代 Git 用于 Windows 的 bash 时还有一个额外的选择

MSYS_NO_PATHCONV=1 cmd /c echo test

Explanation of each attempt每次尝试的解释

TL;DR TL; 博士

The unfortunate answer is in Windows, there are many ways arguments can be parsed, and you have to format your output in bash in such a way that is will be reparsed by the windows program it the way it expects不幸的答案是在 Windows 中,可以通过多种方式解析参数,并且您必须在 bash 中以这样一种方式格式化您的输出,Windows 程序将按照期望的方式对其进行重新解析

Second, third, and forth attempts are all actually identical第二、第三、第四次尝试实际上都是相同的

This is the same as (in cmd) > cmd "/c echo test" .这与(在 cmd 中) > cmd "/c echo test" Windows cmd only uses " quotes, so somewhere between the runtimes, your (in bash) $ cmd '/c echo test' converts all the arguments to "/c echo test" which is happily parses . Windows cmd 仅使用"引号,因此在运行时之间的某处,您的(在 bash 中) $ cmd '/c echo test'将所有参数转换为"/c echo test" ,它很高兴解析.

Since from a bash point of view, the 2nd/3rd/4th attempt are all the same, they all give the same response.因为从 bash 的角度来看,第 2/3/4 次尝试都是相同的,它们都给出了相同的响应。 The surprise " is due to how windows parsing only using " and not ' , hence it is the same as > cmd "/c echo test"令人惊讶的是"是由于 windows 如何仅使用"而不是'解析,因此它与> cmd "/c echo test"

Fifth attempt第五次尝试

$ cmd "/c echo" test is the same as > cmd /c echo" test . (I'm guessing: The space after the /c is optional, so cmd isn't confused by /c echo being the space being literal due to the first quote.) So it is trying to execute the command echo" test which doesn't exist. $ cmd "/c echo" test> cmd /c echo" test 。(我猜: /c后面的空格是可选的,所以 cmd 不会被/c echo作为文字的空格混淆由于第一个引号。)所以它试图执行不存在的命令echo" test The space is interpreted as literal because of the quote.由于引用,空格被解释为文字。 Likewise, if you had done $ cmd "/c echo "test you would get the output "test , because the space is no longer being treats as literal, and no longer part of the command echo同样,如果你已经完成了$ cmd "/c echo "test你会得到输出"test ,因为空间不再被视为文字,也不再是命令echo一部分

Note: > cmd "/c echo" test and > cmd /c echo" test error the same. My guess here is that cmd parsed everything after the /c on its own, so the initial " has no affect, as parsing starts all over again.注意: > cmd "/c echo" test> cmd /c echo" test错误相同。我的猜测是 cmd 自己解析了/c之后的所有内容,所以初始的"没有影响,因为解析开始所有再次。 Chalk that up to special cmd weirdness.将其归结为特殊的cmd怪异之处。


This can actually be reproduced using python for windows, which has nothing to do with msys/mingw/git/bash/glibc/etc...这实际上可以使用 python for windows 重现,这与 msys/mingw/git/bash/glibc/etc 无关......

python -c "import subprocess; subprocess.Popen(['cmd', '/c echo test'])"

I noticed git-bash treats the /c argument like a C: drive:我注意到 git-bash 将/c参数视为 C: 驱动器:

C:\Windows\system32\cmd.exe C:/ echo test

As dbenham found double quotes are added.由于dbenham 发现添加了双引号。 This echos test" for example:这回声test"例如:

cmd /c\ echo\ test

I needed the same line (script) to work in git-bash as well as Cygwin Bash.我需要相同的行(脚本)才能在 git-bash 和 Cygwin Bash 中工作。 The only ways that work are唯一有效的方法是

cmd /c\ echo\ test\&rem\ 

(note that this line needs to end in a space), and (请注意,此行需要以空格结尾),以及

cmd << EOC
echo test
EOC

So escape every space after the /c and add \\&rem\\ at the end of the line (including the trailing space), or just wrap the command in a here document .所以转义/c之后的每个空格在行尾添加\\&rem\\ (包括尾随空格),或者只是将命令包装在here document 中

All this probably depends on the version of git-bash and the specific commands.所有这些可能取决于 git-bash 的版本和特定命令。 :-( :-(

Because you mention that you're using the Git for Windows bundle, I figured I'd point out that it includes winpty , which seems to be quite readable.因为您提到您正在使用Git for Windows包,所以我想我会指出它包含winpty ,它似乎非常易读。

$ winpty echo test
test

$ site="Default Web Site"
$ winpty 'C:\Windows\System32\inetsrv\appcmd' list site "${site}" /text:ID
1

This seems to work under 1.9.5.msysgit.1这似乎在 1.9.5.msysgit.1 下工作

!foo=`bar`
cmd //c \\\\unc-path\\with\\slashes -args \"Quoted Arguments $foo\"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM