собственный ответ eplawless просто и эффективно решает его конкретную проблему: он заменяет все " во всем списке аргументов с \", поэтому Bash требует представления двойных кавычек внутри строки с двойными кавычками.
Чтобы в целом ответить на вопрос о как избежать двойных кавычек внутри строки с двойными кавычками с помощью cmd.exe, интерпретатора командной строки Windows (будь то в командной строке - часто по-прежнему ошибочно называемой приглашением DOS - или в пакетном файле): См. внизу PowerShell.
tl; dr:
Ответ зависит от вызываемой программы:
Вы должны использовать "" при передаче аргумента (другому) пакетному файлу, и вы может использовать "" с приложениями, созданными с помощью компиляторов C / C ++ /. NET Microsoft (которые также принимают \"), которые в Windows включает Python, Node.js и PowerShell (Core) 7+ CLI (pwsh), но не Windows PowerShell (powershell.exe):
- Example:
foo.bat "We had 3"" of rain."
Следующее относится только к пакетным файлам таргетинга:
"" - единственный способ заставить интерпретатор команд (cmd.exe) обрабатывать всю строку в двойных кавычках как одинарный аргумент (хотя это не имеет значения, если вы просто передадите all em > аргументы через другой программе с %*)
К сожалению, однако, сохраняются не только заключающие двойные кавычки (как обычно), но и двойные экранированные кавычки, поэтому получение предполагаемой строки представляет собой двухэтапный процесс; например, если предположить, что строка в двойных кавычках передается как 1-й аргумент, %1:
set "str=%~1" removes the enclosing double-quotes; set "str=%str:""="%" then converts the doubled double-quotes to single ones.
Be sure to use the enclosing double-quotes around the assignment parts to prevent unwanted interpretation of the values.
\" требуется - как only параметр - многими другими программами (например, Ruby, Perl, PHP, а также программами, использующими функция API Windows CommandLineToArgv для анализировать их аргументы командной строки), но использование from cmd.exe небезопасно и не безопасно:
\" is what many executables and interpreters either require - including Windows PowerShell - when passed strings from the outside, on the command line - or, in the case of Microsoft's compilers, support as an alternative to "" - ultimately, though, it's up to the target program to parse the argument list.
- Example:
foo.exe "We had 3\" of rain."
- However, use of
\" can break calls and at least hypothetically result in unwanted, arbitrary execution of commands and/or input/output redirections:
- The following characters present this risk:
& | < >
- For instance, the following results in unintended execution of the
ver command; see further below for an explanation and the next bullet point for a workaround:
foo.exe "3\" of snow" "& ver."
- Для вызова Windows PowerShell CLI,
powershell.exe, \"" и "^"" - надежные, но ограниченные альтернативы (см. раздел «Вызов интерфейса командной строки PowerShell ...» ниже).
Если вы должны использовать \" из cmd.exe, есть только 3 безопасных подхода из cmd.exe, которые, однако, довольно громоздки: Совет шляпу перед TS за его помощь.
Используя (возможно, выборочное) отложенное расширение переменной в вашем пакетном файле, вы можете сохранить литерал \" в переменной и ссылаться на эту переменную внутри "..." строка с синтаксисом !var! - см. полезный ответ TS.
- The above approach, despite being cumbersome, has the advantage that you can apply it methodically and that it works robustly, with any input.
Только с БУКВАЛЬНЫМИ строками - те, которые НЕ включают ПЕРЕМЕННЫЕ - вы получаете аналогичный методический подход: категорически ^-escape все cmd.exe метасимволы: " & | < > и - если вы также хотите подавить переменную расширение - %:
foo.exe ^"3\^" of snow^" ^"^& ver.^"
В противном случае вы должны сформулировать свою строку на основе распознавания того, какие части строки cmd.exe считают не заключенными в кавычки из-за неправильной интерпретации \" как закрывающих разделителей:
в буквальных частях, содержащих метасимволы оболочки: ^ - экранировать их; используя приведенный выше пример, & необходимо ^-экранировать:
foo.exe "3\" of snow" "^& ver."
частями со ссылками на переменные в стиле %...%: убедитесь, что cmd.exe считает их частью "..." строки и, что сами значения переменных не содержат встроенных несбалансированных кавычек - что даже не всегда возможно.
Background
Примечание: это основано на моих собственных экспериментах. Дай мне знать, если я ошибаюсь.
POSIX-подобные оболочки, такие как Bash в Unix-подобных системах, токенизируют список аргументов (строку) перед передачей аргументов индивидуально целевой программе: среди других расширений они разделяют аргумент список на отдельные слова (разделение слов) и удаление кавычек из полученных слов (удаление кавычек). Целевой программе передается массив из отдельных дословных аргументов, т. е. с удаленными синтаксическими кавычками < / сильный>.
В отличие от этого интерпретатор команд Windows, по-видимому, не токенизирует список аргументов, а просто передает единственную строку, содержащую все аргументы, включая символы в кавычках. - в целевую программу.
Однако некоторая предварительная обработка выполняется до того, как в целевую программу будет передана единственная строка: ^ escape-символы. строки вне двойных кавычек удаляются (они экранируют следующий символ), а ссылки на переменные (например, %USERNAME%) сначала интерполируются.
Таким образом, в отличие от Unix, целевая программа несет ответственность за синтаксический анализ, чтобы проанализировать строку аргументов и разбить ее на отдельные аргументы с удаленными кавычками. Таким образом, для разных программ могут потребоваться разные методы экранирования и не существует единого механизма экранирования, который гарантированно работал бы со всеми программами - https: //stackoverflow.com/a/4094897/45375 содержит отличную справочную информацию об анархии, которая представляет собой синтаксический анализ командной строки Windows.
На практике \" очень распространено, но НЕ БЕЗОПАСНО с cmd.exe, как упоминалось выше:
Поскольку сам cmd.exe не распознает \" как экранированные двойные кавычки, он может неверно истолковать более поздние токены в командной строке как не заключенные в кавычки и потенциально интерпретировать их как команды < / em> и / или перенаправления ввода / вывода.
В двух словах: проблема возникает, если какой-либо из следующих символов следует за открывающим или несбалансированным em > \": & | < >; Например:
foo.exe "3\" of snow" "& ver."
cmd.exe видит следующие токены, возникшие в результате неправильной интерпретации \" как обычных двойных кавычек:
"3\"
of
snow" "
- отдых:
& ver.
Поскольку cmd.exe считает, что & ver. не заключен в кавычки, он интерпретирует его как & (оператор последовательности команд), за которым следует имя команды для выполнения (ver. - . игнорируется; ver сообщает информацию о версии cmd.exe ).
Общий эффект:
- Сначала
foo.exe вызывается только с первыми 3 токенами.
- Затем выполняется команда
ver.
Даже в тех случаях, когда случайная команда не причинит вреда, ваша общая команда не будет работать должным образом, поскольку ей передаются не все аргументы.
Многие компиляторы / интерпретаторы распознают ТОЛЬКО \" - например, компилятор GNU C / C ++, Perl, Ruby, PHP, а также программы, использующие _ 74_ Функция Windows API для анализа их аргументов командной строки - и для них там - непростое решение этой проблемы.
По сути, вам нужно заранее знать, какие части вашей командной строки неверно интерпретируются как не заключенные в кавычки, и выборочно ^ экранировать все экземпляры & | < > в этих частях.
Напротив, использование "" БЕЗОПАСНО, но , к сожалению, поддерживается только исполняемыми файлами на основе компилятора Microsoft и пакетными файлами (в случае пакетных файлов, с обсуждаемыми особенностями выше), за исключением PowerShell - см. следующий раздел.
Calling PowerShell's CLI from cmd.exe or POSIX-like shells:
Примечание. В нижнем разделе описано, как цитируется внутри PowerShell.
При вызове извне - например, из cmd.exe, из командной строки или командного файла:
PowerShell [Core] v6 + теперь правильно распознает "" (в дополнение к \"), что одновременно безопасно в использовании и сохраняет пробелы.
pwsh -c " ""a & c"".length " doesn't break and correctly yields 6
Windows PowerShell (устаревшая версия, последняя и последняя версия которой - 5.1) распознает только \" или """ , последний из которых самый надежный вариант из cmd.exe в форме "^""" (хотя внутри PowerShell использует ` как escape в строках, заключенных в двойные кавычки, а также принимает "" - см. нижний раздел), как обсуждается ниже:
Вызов Windows PowerShell из cmd.exe / пакетного файла:
"" ломается, потому что он принципиально не поддерживается:
powershell -c " ""ab c"".length " -> error "The string is missing the terminator"
\" и """ работают в принципе, но небезопасны:
powershell -c " \"ab c\".length " works as intended: it outputs 5 (note the 2 spaces)
- Но это небезопасно, потому что
cmd.exe метасимволы нарушают команду, если не экранированы:
powershell -c " \"a& c\".length " breaks из-за &, который нужно было бы экранировать как ^&
\"" безопасно, но нормализует внутренние пробелы, что может быть нежелательным:
powershell -c " \""a& c\"".length " выводит 4 (!), Потому что 2 пробела нормализованы до 1.
"^"" - лучший выбор для Windows PowerShell, в частности, где он безопасен и сохраняет пробелы, но с PowerShell Core (на Windows) это то же самое, что и \"", то есть пробел - нормализация (как указано, просто используйте там ""). Благодарим Venryx за открытие этого подхода.
powershell -c " "^""a& c"^"".length " работает: не ломается - несмотря на & - и выводит 5, т.е. правильно сохраненные пробелы.
PowerShell Core: pwsh -c " "^""a& c"^"".length " работает, но выводит 4, т.е. нормализует пробелы, как это делает \"".
На Unix-подобных платформах (Linux, macOS) при вызове интерфейса командной строки PowerShell [Core] pwsh из POSIX-подобной оболочки, например bash:
Вы должны использовать \", что, однако, безопасно и сохраняет пробелы:
$ pwsh -c " \"a& c|\".length" # OK: 5
^ можно использовать только как escape-символ в строках без кавычек - внутри строк, заключенных в двойные кавычки, ^ не является специальным и рассматривается как литерал.
- CAVEAT: Use of
^ in parameters passed to the call statement is broken (this applies to both uses of call: invoking another batch file or binary, and calling a subroutine in the same batch file):
^ instances in double-quoted values are inexplicably doubled, altering the value being passed: e.g., if variable %v% contains literal value a^b, call :foo "%v%" assigns "a^^b"(!) to %1 (the first parameter) in subroutine :foo.
- Без кавычек использование
^ с call полностью нарушено, поскольку ^ больше не может использоваться для экранирования специальных символов: например, call foo.cmd a^&b незаметно прерывается (вместо этого передачи литерала a&b тоже foo.cmd, как было бы без call) - foo.cmd даже не вызывается (!), по крайней мере, в Windows 7.
К сожалению, экранирование буквального % - это особый случай, который требует особого синтаксиса в зависимости от того, указана ли строка в командной строке или внутри командный файл; см. https://stackoverflow.com/a/31420292/45375
- The short of it: Inside a batch file, use
%%. On the command line, % cannot be escaped, but if you place a ^ at the start, end, or inside a variable name in an unquoted string (e.g., echo %^foo%), you can prevent variable expansion (interpolation); % instances on the command line that are not part of a variable reference are treated as literals (e.g, 100%).
Как правило, для безопасной работы со значениями переменных, которые могут содержать пробелы и специальные символы:
- Assignment: Enclose both the variable name and the value in a single pair of double-quotes; e.g.,
set "v=a & b" assigns literal value a & b to variable %v% (by contrast, set v="a & b" would make the double-quotes part of the value). Escape literal % instances as %% (works only in batch files - see above).
- Reference: Double-quote variable references to make sure their value is not interpolated; e.g.,
echo "%v%" does not subject the value of %v% to interpolation and prints "a & b" (but note that the double-quotes are invariably printed too). By contrast, echo %v% passes literal a to echo, interprets & as the command-sequencing operator, and therefore tries to execute a command named b.
Also note the above caveat re use of ^ with the call statement.
- External programs typically take care of removing enclosing double-quotes around parameters, but, as noted, in batch files you have to do it yourself (e.g.,
%~1 to remove enclosing double-quotes from the 1st parameter) and, sadly, there is no direct way that I know of to get echo to print a variable value faithfully without the enclosing double-quotes.
- Neil offers a
for-based workaround that works as long as the value has no embedded double quotes; e.g.:
set "var=^&')|;,%!" for /f "delims=" %%v in ("%var%") do echo %%~v
cmd.exe не распознает одиночные кавычки как разделители строк ('...') - они обрабатываются как литералы и обычно не могут использоваться для разграничения строк встроенными пробел; кроме того, из этого следует, что токены, примыкающие к одинарным кавычкам, и любые промежуточные токены рассматриваются cmd.exe как некотируемые и интерпретируются соответственно.
- However, given that target programs ultimately perform their own argument parsing, some programs such as Ruby do recognize single-quoted strings even on Windows; by contrast, C/C++ executables and Perl do not recognize them.
Even if supported by the target program, however, it is not advisable to use single-quoted strings, given that their contents are not protected from potentially unwanted interpretation by cmd.exe.
Quoting from within PowerShell:
Windows PowerShell - это гораздо более продвинутая оболочка, чем cmd.exe, и она была частью Windows для много лет назад (и PowerShell Core также привнес возможности PowerShell в macOS и Linux).
PowerShell работает последовательно внутренне в отношении цитирования:
- внутри строк с двойными кавычками используйте
`" или "", чтобы избежать двойных кавычек
- внутри строк в одинарных кавычках используйте
'', чтобы избежать одинарных кавычек
Это работает в командной строке PowerShell и при передаче параметров в сценарии PowerShell или функции из внутри PowerShell.
(Как обсуждалось выше, для передачи экранированных двойных кавычек в PowerShell извне требуется \" или, что более надежно, \"" - больше ничего не работает).
К сожалению, при вызове внешних программ из PowerShell вы сталкиваетесь с необходимостью учитывать как собственные правила цитирования PowerShell , так и для выхода для цели < / em> программа:
Двойные кавычки внутри двойных строк, заключенных в кавычки:
Рассмотрим строку "3`" of rain", которая внутри PowerShell преобразуется в буквальный 3" of rain.
Если вы хотите передать эту строку внешней программе, вы должны применить экранирование целевой программы в дополнение к PowerShell; скажем, вы хотите передать строку программе C, которая ожидает, что встроенные двойные кавычки будут экранированы как \":
foo.exe "3\`" of rain"
Обратите внимание, как должны присутствовать оба `" - чтобы сделать PowerShell счастливой - и \ - чтобы сделать целевую программу счастливой.
Та же логика применяется к вызову командного файла, где необходимо использовать "":
foo.bat "3`"`" of rain"
Напротив, встраивание одинарных кавычек в двойные кавычки вообще не требует экранирования.
Одиночные кавычки внутри одинарных кавычек не требуют дополнительного экранирования; рассмотрим '2'' of snow', который является представлением 2' of snow в PowerShell.
foo.exe '2'' of snow'
foo.bat '2'' of snow'
PowerShell переводит строки с одинарными кавычками в строки с двойными кавычками перед их передачей в целевую программу.
Однако двойные кавычки внутри одинарных строк, экранирование которых не требуется для PowerShell, по-прежнему нужны для экранирования для целевой программы:
foo.exe '3\" of rain'
foo.bat '3"" of rain'
PowerShell v3 представил волшебный --% параметр, называемый символом остановки анализа, который частично облегчает боль, передавая что-либо после него не интерпретируются для целевой программы, за исключением ссылок на переменные среды в стиле cmd.exe (например, %USERNAME%), которые раскрыты; например.:
foo.exe --% "3\" of rain" -u %USERNAME%
Обратите внимание, как экранировать встроенный " как \" только для целевой программы (а не для PowerShell как \`") достаточно.
Однако такой подход:
- не позволяет экранировать
% символы, чтобы избежать раскрытия переменных среды.
- исключает прямое использование переменных и выражений PowerShell; вместо этого командная строка должна быть встроена в строковую переменную на первом шаге, а затем вызываться с
Invoke-Expression на втором.
альтернативным обходным путем *, который решает эту проблему, является вызов через cmd /c с одним аргументом, содержащим всю командную строку:
cmd /c "foo.exe `"3\`" of rain`" -u $env:USERNAME"
Таким образом, несмотря на множество усовершенствований, PowerShell не упростил экранирование при вызове внешних программ - наоборот. Однако он ввел поддержку строк в одинарных кавычках.
Если вы не против установки стороннего модуля (созданного мной), Native module ( Install-Module Native) предлагает обратную и прямую совместимую вспомогательную функцию ie, которая устраняет необходимость в дополнительном экранировании и содержит важные приспособления для высокопрофильных интерфейсов командной строки в Windows:
# Simply prepend 'ie' to your external-program calls.
ie foo.exe '3" of rain' -u $env:USERNAME
person
mklement0
schedule
14.07.2015