当前位置: 首页 > 面试题库 >

有没有办法防止Windows命令行中的env变量扩展百分比?

郎翔
2023-03-14
问题内容

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

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

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

虽然它在git
bash中可以正常工作,但不能很好地使用cmd%cd%Windows外壳程序将其扩展到当前工作目录($PWD在bash中等效)。

因此,当通过运行该命令时cmd,我在第一栏中看到当前的工作目录,而不是提交日期! 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:\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'})

cmd在Windows上使用when 由节点执行。

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

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

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

但是,这引入了一个冗余空间(我之前删除了另一个空间,%s但这仍然是一个hack,需要手动干预)。

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

我发现了有关使用%%^%转义的信息,%但此处不是解决方案

# 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

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


问题答案:

如果你真的 需要 得到 参与(这是不可能的,因为你的国家,你想要的命令与Windows的工作都cmd.exe
bash)的,立即考虑下面的解决方案; 有关 绕过 该问题 的无 替代方案 __,请参阅 底部 的解决方案。

在帽子的提示MC ND为提高我原来通过建议配售双引号的方法%实例,而不是潜在的变量名 之间 %的实例和建议澄清重execFileSync

“转义” %字符。对于cmd.exe

如MC
ND的回答所述,您从技术上讲不能%在Windows命令提示符下转义(可以使用批处理文件%%,但是从其他环境(如Node.js)调用Shell命令时,此操作无效,并且通常无法跨平台)。

但是, 解决方法在每个%实例周围加上 双引号

// 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"%"不会扩展)。

之所以有效,是因为在由目标程序处理时,多余的双引号最终会从字符串中删除:

  • Windows :(git.exe大概通过C运行时)然后负责从组合字符串中删除多余的双引号。

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

    • 警告 :通常在命令中使用 双引号 意味着您需要注意类似POSIX的shell,$它们会对-prefixed令牌执行可能不需要的扩展(此处不存在问题);但是,为了保持Windows兼容,您 必须 使用双引号。

从技术上讲,将此技术应用于双引号字符串会将其分成一系列双引号 子字符串,这些子字符串 散布在 未加引号的
%实例中。类似于POSIX的shell仍将其识别为 单个 字符串-子字符串被双引号引起来并且直接与%实例邻接。(如果将这种技术应用于
未加引号的
字符串,则逻辑是相反的:实际上是在双引号%实例中进行拼接。)然后,将子字符串周围的双引号(被视为语法元素而不是字符串的一部分)当子字符串连接在一起以形成单个文字以传递给目标程序时,将其删除。

通过完全避免使用壳来绕过该问题

注意 :以下版本基于execFile[Sync],仅在 调用 外部可执行文件
时才有效(在OP的情况下是这样:git.exe)-相比之下,对于调用 shell内置文件 (内部命令)或Windows 批处理文件
,您无法避免exec[Sync],因此无法通过cmd.exe(在视窗)。[1]

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

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

注意如何的参数,必须提供 单独 作为一个元素 阵列 ,并且 没有嵌入引用

[1]在Windows上,不能直接使用调用脚本文件(例如Python脚本)execFile[Sync],而是可以将解释器可执行文件(例如python)作为要执行的文件,而将脚本文件作为参数。在类似Unix的平台上,您
可以
直接调用脚本,只要它们具有shebang行并标记为可执行文件即可。
execFile[Sync] 可以 用来调用Windows 批处理文件 ,但cmd.exe总是像一样插值参数exec[Sync]



 类似资料:
  • 我想读取Dockerfile中的变量,该变量在文件中定义。有什么办法可以做到这一点吗? 这是我的DockerFile:

  • 在Dart(2.15.0)中,我试图通过定义toJson方法将jsonEncode与枚举一起使用。它不起作用。 根据文档,将查找方法。 当直接在枚举上调用时,扩展可以工作,但是不知何故jsonEncode没有找到toJSON。 Dart如何获取枚举的“值”https://dart.dev/guides/language/extension-methods 知道这是一个错误还是预期的行为吗? 否则,

  • 问题内容: 假设我有以下情况: 有没有一种方法可以保证实现的任何类也必须扩展?我不想创建一个抽象类,因为我希望能够以类似的方式混合其他一些接口。 例如: 问题答案: Java接口无法扩展类,这很有意义,因为类包含无法在接口内指定的实现细节。 解决此问题的正确方法是通过将接口也完全从实现中分离出来。所述等可以扩展接口以迫使程序员来实现相应的方法。如果要在所有实例之间共享代码,则可以将(可能是抽象的)

  • 我有一个非常简单的练习,我注册客户端名称(字符串),我使用数组来做到这一点,所以当我添加一个新的我将使用另一个辅助数组,然后增加原来的长度,或者我将使用System.array复制,有没有其他方法,逐渐增加数组长度,因为你需要添加元素到该数组,不涉及辅助数组?

  • 我正在做一个Jenkins的工作,它接受来自用户的一些参数。我遇到了一个不希望的行为:在我的脚本有机会读取环境变量之前,Jenkins似乎在参数环境变量中扩展了环境变量引用。 如果用户输入 作为参数,我的脚本实际看到的是 的内容;环境变量已展开。如果输入的值包含 我的脚本只能看到一个 。但是,如果它包含环境中不存在,则该值将保持不变(不会引发任何类型的错误)。 这很不方便,因为它甚至出现在密码字段

  • 问题内容: 我想将背景URL存储在自定义属性(CSS变量)中,并将其与background属性一起使用。但是,当使用字符串作为参数时,我找不到插值的方法。 这是我的示例代码: 我知道可以使用插值函数在Sass或LESS中轻松完成此操作,但我很好奇是否有一种无需任何预处理器的方法。 问题答案: 您可以使用大多数CSS函数执行插值,包括的示例。实际上,插值是自定义属性的主要功能之一。 但是,您不能使用