Есть ли способ предотвратить процентное расширение переменной env в командной строке Windows?
Я использую следующую команду git в git bash в Windows:
git log --format="%C(cyan)%cd%Creset %s" --date=short -5
Отображает дату принятия (%cd
) с последующим сообщением фиксации (%s
). Дата фиксации оборачивается цветными маркерами: %C(cyan)
начать цветной вывод и %Creset
остановить цветной вывод.
Хотя он хорошо работает в Git Bash, он не очень хорошо с cmd
: %cd%
расширяется оболочкой Windows в текущий рабочий каталог (эквивалент $PWD
в баш).
Следовательно, когда эта команда запускается через 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
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'})
который выполняется узлом, используя cmd
когда на винде).
Простой обходной путь может заключаться в том, чтобы ввести пространство для предотвращения %cd%
быть найденным, т.е. изменить
git log --format="%C(cyan)%cd%Creset %s" --date=short -5
в
git log --format="%C(cyan)%cd %Creset%s" --date=short -5
Однако это ввело избыточное пространство (я удалил еще один пробел перед %s
но это все же взлом, и требует ручного вмешательства).
Есть ли способ предотвратить расширение оболочкой Windows?
Я нашел информацию об использовании %%
или же ^%
чтобы избежать %
но они не являются решением здесь:
# 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, без создания избыточных символов, либо с функцией escape в javascript, чтобы экранировать универсальную команду UNIX-y для Windows, чтобы предотвратить расширения (если такая функция escape может быть создана).
2 ответа
Чтобы предоставить альтернативу полезному ответу MC ND:
Если вам действительно нужно включить оболочку (что маловероятно, потому что вы заявляете, что хотите, чтобы команда работала как с Windows' cmd.exe
и Bash), рассмотрите решение сразу ниже; для альтернативы без оболочки, которая обходит проблему, см. решение внизу.
Наконечник шляпы MC ND для улучшения моего оригинального подхода, предлагая поместить двойные кавычки вокруг %
экземпляры, а не имена потенциальных переменных между %
случаи, и для предложения разъяснения о execFileSync
,
"Высвобождение" %
символы. за cmd.exe
Как указано в ответе MC ND, вы не можете технически избежать %
в командной строке Windows (внутри командных файлов вы можете использовать %%
, но это не работает при вызове команд оболочки из других сред, таких как Node.js, и обычно не работает на разных платформах).
Тем не менее, обходной путь заключается в размещении двойных кавычек вокруг каждого %
экземпляр:
// 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-подобные оболочки, такие как Bash): сама оболочка заботится об удалении двойных кавычек перед передачей их целевой программе.
- Предостережение: использование двойных кавычек в вашей команде в целом означает, что вам нужно следить за POSIX-подобными оболочками, выполняющими потенциально нежелательные расширения на
$
-префиксированные токены (здесь не проблема); однако, чтобы оставаться Windows-совместимым, вы должны использовать двойные кавычки.
- Предостережение: использование двойных кавычек в вашей команде в целом означает, что вам нужно следить за POSIX-подобными оболочками, выполняющими потенциально нежелательные расширения на
Технически, применение этого метода к строке в двойных кавычках разбивает ее на последовательность подстрок в двойных кавычках, перемежающихся с кавычками %
экземпляров. POSIX-подобные оболочки по-прежнему распознают это как одну строку - подстроки заключаются в двойные кавычки и непосредственно примыкают к %
экземпляров. (Если вы примените технику к строке без кавычек, логика обратная: вы эффективно объединяете в двойных кавычках %
экземпляры.) Двойные кавычки вокруг подстрок, которые считаются синтаксическими элементами, а не частью строки, затем удаляются, когда подстроки соединяются вместе, чтобы сформировать один литерал для передачи целевой программе.
Обойти проблему, избегая оболочки вообще
Примечание: следующее основано на execFile[Sync]
, который работает только для вызова внешних исполняемых файлов (что верно в случае OP: git.exe
) - напротив, для вызова встроенных команд оболочки (внутренних команд) или пакетных файлов Windows нельзя избежать exec[Sync]
и, таким образом, интерпретация cmd.exe
(на Windows). [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]
,
Короче, Вы не можете сделать это или, по крайней мере, нет общего метода
обратите внимание, я был неправ. Ответ mklement0 указал путь для общего решения.
Конечно, вы можете использовать ^
не для того, чтобы избежать знака процента (вы не можете избежать знака процента на уровне командной строки), а для отделения знака процента от имени переменной, чтобы он не был обнаружен в качестве раскрываемой переменной. То есть для вашего случая достаточно использовать
git log --format="%C(cyan)%cd^%Creset %s" --date=short -5
но, как вы указали, каретка не используется синтаксическим анализатором и включается в выходную строку.
Таким образом, любые "escape" символы будут включены в вывод как в cmd
а также bash
, но это может быть решено для этого конкретного (или аналогичного) случая, используя
process.env.cd = '%cd%'
require('child_process').execSync(
'git log --format="%C(cyan)%cd%Creset %s" --date=short -5'
, {stdio: 'inherit'}
)
По сути, код выполняет назначение поддельного значения cd
переменная окружения, меняя ее на литерал %cd%
Итак, когда cmd
parser выполняет раскрытие переменной, правильное значение заканчивается в командной строке.
Но, может быть (я не проверял, как / что git
код делает) изменение cd
переменная может мешать. Таким образом, также для этого случая, вместо изменения значения cd
переменная, которую вы можете использовать
process.env['C(cyan)'] = '%C(cyan)%';
Зачем? Когда cmd
анализатор обрабатывает командную строку, он сравнивает начало строки формата с существующей переменной, выполняет расширение и в том же процессе использует начальный знак процента в %cd%
переменная, поэтому она не расширяется.