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

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

问题描述

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

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

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

它显示提交日期(%cd)和提交信息(%s).提交日期用颜色标记包裹:%C(cyan) 开始彩色输出,%Creset 停止彩色输出.

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.

虽然它在 git bash 中工作正常,但它在 cmd 中表现不佳:%cd% 被 Windows shell 扩展到当前工作目录(相当于 $PWD 在 bash 中).

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).

因此,当通过 cmd 运行该命令时,我看到当前工作目录显示而不是第一列中的提交日期!git 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

命令:

D:gitsomeFolderCreset commit msg
D:gitsomeFolderCreset commit msg
D:gitsomeFolderCreset commit msg
D:gitsomeFolderCreset commit msg
D:gitsomeFolderCreset commit msg

实际上,我自己从来没有直接使用 cmd,我在编写 nodejs (0.12) 脚本时发现了这种行为

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'})

在 Windows 上使用 cmd 由节点执行.

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

一个简单的解决方法可能是引入一个空格来防止 %cd% 被发现,即更改

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

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

然而这引入了一个冗余空间(我在%s之前删除了另一个空间,但它仍然是一个hack,需要人工干预).

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

有没有办法防止 Windows shell 扩展?

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:gitsomeFolder commit msg
%D:gitsomeFolder commit msg
%D:gitsomeFolder commit msg
%D:gitsomeFolder commit msg
%D:gitsomeFolder commit msg

理想的解决方案应该是兼容 bash 和 cmd,不会产生多余的字符,或者是 javascript 中的转义函数来转义 Windows 的通用 UNIX-y 命令以防止扩展(如果可以创建这样的转义函数).

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).

推荐答案

MC ND 的有用回答提供替代方案:

如果您真的需要shell 参与(这不太可能,因为您声明您希望该命令同时与Windows 的 cmd.exe and Bash),请考虑下面的解决方案;要无壳替代绕过问题,请参阅底部的解决方案.

If you really need to get the shell involved (which is unlikely, because you state that you want the 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.

感谢 MC ND 通过建议放置双引号来改进我原来的方法围绕 % 实例而不是潜在的变量名称 between % 实例,并建议对 execFileSync 进行澄清.

Tip of the hat to MC ND 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.

MC ND 的回答所述,从技术上讲,您无法在 Windows 命令中转义 %提示(在批处理文件中,您可以使用 %%,但这在从其他环境(例如 Node.js)调用 shell 命令时不起作用,并且通常无法跨平台运行).

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())

插入的双引号会阻止 cmd.exe 将诸如 %cd% 之类的标记识别为变量引用 ("%"cd"%" 不会被扩展).

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(大概是通过 C 运行时)然后负责从组合字符串中去除额外的双引号.

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

类 Unix(类 POSIX 的 shell,例如 Bash):shell 本身负责在将双引号传递给目标程序之前移除双引号.

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.

  • 警告:在您的命令中使用双引号通常意味着您需要注意类似 POSIX 的 shell 在 $<上执行可能不需要的扩展/code>-prefixed 标记(这里不是问题);但是,为了保持与 Windows 兼容,您必须使用双引号.
  • 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.

从技术上讲,将此技术应用于双引号字符串将其分解为一系列双引号子字符串,中间夹杂着未引用 %实例.类似于 POSIX 的 shell 仍然将其识别为 单个 字符串 - 子字符串被双引号括起来并直接紧靠 % 实例.(如果您将该技术应用于 未加引号 字符串,则逻辑相反:您实际上是在双引号 % 实例中进行拼接.)子字符串周围的双引号被认为是语法元素而不是字符串的一部分,然后当子字符串连接在一起形成要传递给目标程序的单个文字时将被删除.

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.

注意:以下内容建立在 execFile[Sync] 之上,仅适用于调用外部可执行文件(这在 OP 的情况下是正确的:git.exe) - 相比之下,用于调用 shell builtins(内部命令)或 Windows 批处理文件,您无法避免 exec[Sync] 并因此被 cmd.exe 解释(在 Windows 上).[1]

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

如果您使用execFileSync 而不是 execSyncshell(Windows 上的 cmd.exe)将不涉及,因此您不需要担心转义 % 字符. 或任何其他 shell 元字符,就此而言:

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] 在 Windows 上,不能使用 execFile[Sync] 直接调用脚本文件(例如 Python 脚本),但您可以改为传递解释器可执行文件(例如,python) 作为要执行的文件,脚本文件作为参数.在类 Unix 平台上,您可以直接调用脚本,只要它们具有 shebang line 并标记为可执行文件.
execFile[Sync] 可以用于调用 Windows 批处理文件,但 cmd.exe 总是插入参数,与 exec[Sync] 一样.

[1] On Windows, script files (e.g., Python scripts) cannot be called directly with execFile[Sync], but you can instead pass the interpreter executable (e.g., python) as the 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 marked as executable.
execFile[Sync] can be used to invoke Windows batch files, but cmd.exe invariably interpolates the arguments, as with exec[Sync].

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

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