有没有办法防止百分比扩展的env变量在Windows命令行? [英] Is there a way to prevent percent expansion of env variable in Windows command line?

查看:430
本文介绍了有没有办法防止百分比扩展的env变量在Windows命令行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Windows上使用git bash中的git命令:

  git log --format =%C (青色)%cd%Creset%s--date = short -5 

%cd ),然后是提交消息(%s )。提交日期用颜色标记包裹:%C(青色)开始彩色输出,%Creset 停止彩色输出。



虽然在git bash中工作正常,但它不能很好地与 cmd %cd%被Windows shell扩展到当前工作目录(相当于bash中的 $ PWD )。



因此,当该命令通过 cmd 运行时,我看到当前工作目录而不是提交日期在第一列! strong>
git bash:

  2015-10-08 commit msg 
2015-10-08 commit msg
2015-10-07 commit msg
2015-10-06 commit msg
2015-10-06 commit msg

cmd:

  D:\git\someFolderCreset commit msg 
D:\git\someFolderCreset commit msg
D:\git\someFolderCreset commit msg
D:\git\someFolderCreset commit msg
D:\ git \someFolderCreset commit msg

其实,我从来不使用 cmd 直接自己,我发现这个行为,当编写一个nodejs(0.12)脚本,其中我有

  require('child_process ').execSync('git log --format = ...',{stdio:'inherit'})


$ b b

当在Windows上使用 cmd 时,节点将执行此操作。



引入空格以防止%cd%被找到,即更改

  git log --format =%C(cyan)%cd%Creset%s--date = short -5 


b $ b

  git log --format =%C(cyan)%cd%Creset%s --date = short -5 

但是这引入了一个冗余空间c $ c>%s 但它仍然是一个黑客,需要手动干预)。



有一种方法来防止扩展的Windows shell?



我有找到关于使用 %% ^% 但它们不是这里的解决方案:

 #产生多余的^字符
git log --format =%C(青色)^%cd ^%Creset%s--date =短-5

^ 2015-10-08 ^ commit msg
^ 2015-10-08 ^ commit msg
^ 2015-10-07 ^ commit msg
^ 2015-10-06 ^ commit msg
^ 2015-10-06 ^ commit msg

#看来扩展是在命令解析时完成的
git log --format =%C(cyan)%% cd %% Creset%s--date = short -5

%D:\git\someFolder commit msg
%D:\git\someFolder commit msg
%D:\git\someFolder commit msg
%D:\git\someFolder commit msg
%D:\git\someFolder commit msg

理想的解决方案应该是与bash和cmd兼容,而不生成冗余字符,或者javascript中的转义函数来转义通用UNIX-y命令以防止扩展(如果这样的话)可以创建一个转义函数)。

解决方案

提供的替代方法MC ND的实用答案



如果您真的需要 (这是不太可能的,因为您声明您希望shell命令与Windows的 cmd.exe ,考虑下面紧接着的解决方案;



提示: MC NC 改善我的原始方法,建议在实例之间放置双引号,而不是 实例,并建议澄清 execFileSync






Escaping字符。 cmd.exe



%),你不能在技术上转义 %,但是在从其他环境(如Node.js)调用shell命令时不起作用,通常不能跨平台工作)。



解决方法在每个实例周围加双引号:

  //输入shell命令。 
var shellCmd ='git log --format =%C(cyan)%cd%Creset%s--date = short -5'

//放置双引号在每个'%'的每一端
//这产生(不漂亮,但它的工作原理):
// git log --format =%C(cyan)%cd %Creset%s--date = short -5
var escapedShellCmd = shellCmd.replace(/%/ g,'%')

//这两个Windows和类似Unix的平台:
console.log(require('child_process')。execSync(escapedShellCmd).toString())

插入的双引号可防止 cmd.exe 识别%cd%作为变量引用(%cd%将不会扩展)。



这是有效的,因为额外的双引号在目标程序处理时最终从字符串中删除:




  • Windows git.exe (可能是通过C运行时)


  • 类似Unix的




    • 注意:使用双引号通常意味着你需要注意类似POSIX的shell在 $ 上执行潜在的不必要的扩展 - 问题在这里);但是,为了保持Windows兼容性,您必须使用双引号。


$ b $从技术上讲,将此技术应用于双引号字符串会将其转换为一个双引号的子字符序列,其间用 unquoted 个实例。类似POSIX的shell仍将其识别为单个字符串 - 子字符串是双引号的,并且直接邻接实例。 (如果将此技术应用于无引号字符串,则逻辑反转:您在双引号实例中有效拼接。)当子串连接在一起以形成单个文本传递到目标程序时,将删除围绕子串的双引号,而这些子串被视为句法元素而不是字符串的一部分。






通过避免shell完全绕过问题。



注意:以下内容构建在 execFile [Sync] 上,仅适用于调用外部可执行文件 strong>(这在OP的情况下是真的: git.exe ) - 对于调用shell内建(内部命令)或Windows批处理文件,你不能避免 exec [Sync] ,从而解释为 cmd.exe (在Windows上)。 [1]



如果您使用 execFileSync 而不是 execSync shell( cmd.exe 在Windows上)不会涉及,因此您不必担心转义字符。任何其他shell元字符,因为:

  require('child_process')。execFileSync('git',
['log',
'--format =%C(cyan)%cd%Creset%s',
'--date = short',
'-5'], stdio:'inherit'})

注意如何单独提供参数 >作为数组的元素无嵌入引用






[1]在Windows上,不能直接调用脚本文件(例如Python脚本),而是可以将解释器可执行文件作为要执行的文件,将脚本文件作为参数传递。在UNIX类似平台上,您可以直接调用脚本,只要它们有一个shebang行并且可直接执行。

技术 execFile [Sync] 允许您直接调用Windows批处理文件,但这样做没有优势 - cmd.exe 始终内插参数,以及 - 至少节点v4.1.2 - 嵌入式双引号不正确转义为 \,而批处理文件需要


I'm using the following git command in git bash on Windows:

git log --format="%C(cyan)%cd%Creset %s" --date=short -5

It displays commit date (%cd) followed by commit message (%s). Commit date is wrapped with color markers: %C(cyan) to start colored output and %Creset to stop colored output.

While it works fine in git bash, it doesn't do well with cmd: %cd% is expanded by Windows shell into current working directory (equivalent of $PWD in bash).

Hence when that command is run via cmd, I see current working directory displayed instead of commit date in the first column! git bash:

2015-10-08 commit msg
2015-10-08 commit msg
2015-10-07 commit msg
2015-10-06 commit msg
2015-10-06 commit msg

cmd:

D:\git\someFolderCreset commit msg
D:\git\someFolderCreset commit msg
D:\git\someFolderCreset commit msg
D:\git\someFolderCreset commit msg
D:\git\someFolderCreset commit msg

Actually, I never use cmd directly myself, I found this behavior while writing a nodejs (0.12) script in which I had

require('child_process').execSync('git log --format=...', {stdio: 'inherit'})

which gets executed by node using the cmd when on Windows).

A simple workaround could be to introduce a space to prevent %cd% being found, i.e. change

git log --format="%C(cyan)%cd%Creset %s" --date=short -5

to

git log --format="%C(cyan)%cd %Creset%s" --date=short -5

However this introduced a redundant space (I deleted another space before %s but it's still a hack, and requires manual intervention).

Is there a way to prevent expansion by the Windows shell?

I've found information about using %% or ^% to escape the % but they are not the solution here:

# produces superfluous ^ characters
git log --format="%C(cyan)^%cd^%Creset %s" --date=short -5

^2015-10-08^ commit msg
^2015-10-08^ commit msg
^2015-10-07^ commit msg
^2015-10-06^ commit msg
^2015-10-06^ commit msg

# seems the expansion is done at command parse time
git log --format="%C(cyan)%%cd%%Creset %s" --date=short -5

%D:\git\someFolder commit msg
%D:\git\someFolder commit msg
%D:\git\someFolder commit msg
%D:\git\someFolder commit msg
%D:\git\someFolder commit msg

The ideal solution should be either compatible with bash and cmd, without producing redundant characters, or an escape function in javascript to escape the generic UNIX-y command for Windows to prevent the expansions (if such an escape function can be created).

解决方案

To provide an alternative to MC ND's helpful answer:

If you really need to get the shell involved (which is unlikely, because you state that you want the shell command to work both with Windows' cmd.exe and Bash), consider the solution immediately below; for a shell-less alternative that bypasses the problem, see the solution at the bottom.

Tip of the hat to MC NC for improving my original approach by suggesting placing double-quotes around % instances rather than the potential variable names between % instances, and for suggesting a clarification re execFileSync.


"Escaping" % chars. for cmd.exe

As stated in MC ND's answer, you cannot technically escape % at the Windows command prompt (inside batch files you can use %%, but that doesn't work when invoking shell commands from other environments such as Node.js, and generally wouldn't work across platforms).

However, the workaround is to place double-quotes around each % instance:

// Input shell command.
var shellCmd = 'git log --format="%C(cyan)%cd%Creset %s" --date=short -5'

// Place a double-quote on either end of each '%'
// This yields (not pretty, but it works):
//   git log --format=""%"C(cyan)"%"cd"%"Creset "%"s" --date=short -5
var escapedShellCmd = shellCmd.replace(/%/g, '"%"')

// Should work on both Windows and Unix-like platforms:
console.log(require('child_process').execSync(escapedShellCmd).toString())

The inserted double-quotes prevent cmd.exe from recognizing tokens such as %cd% as variable references ("%"cd"%" won't get expanded).

This works, because the extra double-quotes are ultimately stripped from the string when processed by the target program:

  • Windows: git.exe (presumably via the C runtime) then takes care of stripping the extra double-quotes from the combined string.

  • Unix-like (POSIX-like shells such as Bash): the shell itself takes care of removing the double-quotes before passing them to the target program.

    • Caveat: Using double-quotes in your command in general means that you need to watch out for POSIX-like shells performing potentially unwanted expansions on $-prefixed tokens (not an issue here); however, in order to remain Windows-compatible you must use double-quotes.

Technically, applying this technique to a double-quoted string breaks it into a sequence of double-quoted substrings interspersed with unquoted % instances. POSIX-like shells still recognize this as a single string - the substrings are double-quoted and directly abut the % instances. (If you apply the technique to an unquoted string, the logic is reversed: you're effectively splicing in double-quoted % instances.) The double-quotes around the substrings, which are considered syntactical elements rather than part of the string, are then removed when the substrings are joined together to form the single literal to pass to the target program.


Bypassing the problem by avoiding the shell altogether

Note: The following builds on execFile[Sync], which only works for calling external executables (which is true in the OP's case: git.exe) - for calling shell builtins (internal commands) or Windows batch files, you cannot avoid exec[Sync] and thus interpretation by cmd.exe (on Windows).[1]

If you use execFileSync rather than execSync, the shell (cmd.exe on Windows) will NOT be involved and thus you needn't worry about escaping % chars. or any other shell metacharacters, for that matter:

require('child_process').execFileSync('git', 
   [ 'log', 
     '--format=%C(cyan)%cd%Creset %s',
     '--date=short',
     '-5' ], {stdio: 'inherit'})

Note how the arguments must be supplied individually as elements of an array, and without embedded quoting.


[1] On Windows, script files (e.g., Python scripts) cannot be called directly, but you can instead pass the interpreter executable as file to execute, and the script file as an argument. On Unix-like platforms you can call scripts directly, as long as they have a shebang line and are directly executable.
Technically, execFile[Sync] allows you to invoke a Windows batch file directly, but there is no advantage to doing so - cmd.exe invariably interpolates the arguments, and - at least as of Node v4.1.2 - embedded double-quotes are incorrectly escaped as \", whereas batch files require "".

这篇关于有没有办法防止百分比扩展的env变量在Windows命令行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆