собственный ответ eplawless просто и эффективно решает его конкретную проблему: он заменяет все "
экземпляры во всем списке аргументов на \"
, так как Bash требует двойных кавычек в двойных кавычках строка для представления.
Чтобы вообще ответить на вопрос как избежать двойных кавычек внутри строки в двойных кавычках, используя cmd.exe
, интерпретатор командной строки Windows (будь то в командной строке - часто все еще по ошибке называют «Приглашение DOS» (или в пакетном файле): См. Внизу PowerShell .
ТЛ; др
Вы должны использовать ""
при передаче строки в (другой) пакетный файл и вы может использовать ""
с приложениями, созданными с помощью Microsoft компиляторов C / C ++ /. NET (которые также принимают \"
) который в Windows включает Python и Node.js :
\"
требуется требуется - в качестве единственной опции - многими другими программами (например, Ruby, Perl и даже собственной PowerShell от Microsoft (!)) , но ЕГО ИСПОЛЬЗОВАНИЕ - НЕ БЕЗОПАСНО
\"
- это то, что для многих исполняемых файлов и интерпретаторов требуется - включая собственный PowerShell от Microsoft при передаче строк извне - или, в случае компиляторов Microsoft, поддержка в качестве альтернативы ""
- в конечном счете, однако, это целевая программа для анализа списка аргументов.
- Пример:
foo.exe "We had 3\" of rain."
- ОДНАКО, ИСПОЛЬЗОВАНИЕ
\"
МОЖЕТ ПРИВЕСТИ К НЕСКОЛЬКОМ, АРБИТРАЖНОМУ ИСПОЛНЕНИЮ КОМАНД и / или ВХОДНЫМ / ВЫХОДНЫМ НАПРАВЛЕНИЯМ :
- Следующие символы представляют этот риск:
& | < >
- Например, следующее приводит к непреднамеренному выполнению команды
ver
; см. ниже объяснение и следующий пункт для обходного пути:
foo.exe "3\" of snow" "& ver."
- Для PowerShell в Windows только ,
\""
- надежная альтернатива.
Если вы должны использовать \"
, есть только 3 безопасных подходов , которые, однако, довольно громоздки : Совет шляпы TS за помощь.
Используя (возможно выборочное ) расширение отложенной переменной в вашем пакетном файле, вы можете сохранить литерал \"
в переменной и ссылаться на эту переменную внутри строки "..."
, используя синтаксис !var!
- см. полезный ответ TS .
- Приведенный выше подход, несмотря на его громоздкость, имеет то преимущество, что вы можете применять его методично и что он работает надежно с любым вводом.
Только с ЛИТЕРАЛЬНЫМИ строками - теми, которые НЕ включают ПЕРЕМЕННЫЕ - вы получаете такой же методический подход: категорически ^
-эскейп все cmd.exe
метасимволы: " & | < >
и - если вы также хотите подавить расширение переменной - %
:
foo.exe ^"3\^" of snow^" ^"^& ver.^"
В противном случае вы должны сформулировать свою строку на основе распознавания, какие части строки cmd.exe
считает не заключенными в кавычки из-за неправильного толкования \"
как закрывающих разделителей:
в литерал частей, содержащих метасимволы оболочки: ^
- экранировать их; используя приведенный выше пример, это &
, который должен быть ^
-эскапед:
foo.exe "3\" of snow" "^& ver."
порциями с %...%
ссылками на переменные в стиле : убедитесь, что cmd.exe
считает их частью "..."
строки и , что значения переменной делают сами по себе не имеют встроенных несбалансированных кавычек - , что даже не всегда возможно .
Для справочной информации, читайте дальше.
Фон
Примечание: это основано на моих собственных экспериментах. Дайте мне знать, если я ошибаюсь.
POSIX-подобные оболочки, такие как Bash, в Unix-подобных системах маркируют список аргументов (строку) перед передачей аргументов индивидуально целевой программе: среди других расширений они разбивают список аргументов на отдельные слова ( разделение слов) и удалить символы цитирования из результирующих слов (удаление кавычек). То, что передается целевой программе, это концептуально массив отдельных аргументов с удаленными (требующими синтаксиса) кавычками.
Напротив, интерпретатор команд Windows, по-видимому, не маркирует список аргументов и просто передает одну строку, содержащую все аргументы - включая символы кавычек. - к целевой программе.
Однако некоторая предварительная обработка выполняется до того, как одна строка передается целевой программе: ^
escape-символы. вне строк в двойных кавычках удаляются (они избегают следующего символа), а ссылки на переменные (например, %USERNAME%
) интерполируются сначала.
Таким образом, в отличие от Unix, целевая программа должна проанализировать, чтобы проанализировать строку аргументов и разбить ее на отдельные аргументы с удаленными кавычками.
Таким образом, различным программам гипотетически могут потребоваться разные методы экранирования и , и нет единого механизма экранирования, который гарантированно работает со всеми программами - https://stackoverflow.com/a/4094897/45375 содержит отличные сведения об анархии, которая заключается в разборе командной строки Windows.
На практике \"
очень распространено, но НЕ БЕЗОПАСНО , как упоминалось выше:
Поскольку cmd.exe
само по себе не распознает \"
как экранированную двойную кавычку, он может неправильно интерпретировать более поздние токены в командной строке как без кавычек и потенциально интерпретировать их как команды и / или перенаправления ввода / вывода .
В двух словах: проблемные поверхности, если любой из следующих символов следует за открытием или неуравновешенным \"
: & | < >
; например:
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 ++, Python, Perl, Ruby, даже собственный PowerShell от Microsoft при вызове из cmd.exe
- и, за исключением PowerShell с \""
, для них не существует простого решения этой проблемы.
По сути, вам нужно заранее знать, какие части вашей командной строки неверно истолкованы как не заключенные в кавычки, и выборочно ^
исключить все экземпляры & | < >
в этих частях.
Напротив, использование ""
БЕЗОПАСНО , но , к сожалению, поддерживается только исполняемыми файлами и пакетными файлами на базе компилятора Microsoft (в случае пакетных файлов с причуды, обсужденные выше).
Напротив, PowerShell , когда вызывается извне - например, из cmd.exe
, из командной строки или из пакетного файла - распознает только \"
и в Windows более надежный \""
, хотя внутренне PowerShell использует `
в качестве escape-символа в строках в двойных кавычках и также принимает ""
; например:
powershell -c " \"ab c\".length"
работает (вывод 4
), как и более устойчивый
powershell -c " \""ab c\"".length"
но powershell -c " ""ab c"".length"
перерывы .
Дополнительная информация
^
может использоваться только как escape-символ в без кавычек строк - внутри строк в двойных кавычках ^
не является специальным и трактуется как литерал .
- CAVEAT : Использование
^
в параметрах, передаваемых в оператор call
, нарушено (это относится к обоим применениям call
: вызов другого пакетного файла или двоичного файла и вызов подпрограммы в том же пакетном файле):
^
экземпляры в двойные кавычки значения необъяснимо удвоены , изменяя передаваемое значение: например, если переменная %v%
содержит буквальное значение a^b
, call :foo "%v%"
назначает "a^^b"
(!) На %1
(первый параметр) в подпрограмме :foo
.
- Без кавычек использование
^
с call
означает в целом , поскольку ^
больше не может использоваться для экранирования специальных символов : например, , call foo.cmd a^&b
тихо прерывается (вместо передачи буквального a&b
тоже foo.cmd
, как было бы без call
) - foo.cmd
никогда даже не вызывается (!), По крайней мере в Windows 7.
Экранирование литерала %
- это особый случай * К сожалению, , для которого требуется особый синтаксис в зависимости от того, указана ли строка в командной строке против . внутри пакетного файла ; см https://stackoverflow.com/a/31420292/45375
- Суть этого: внутри командного файла используйте
%%
. В командной строке %
нельзя экранировать, но если вы поместите ^
в начале, конце или внутри имени переменной в строке без кавычек (например, echo %^foo%
), вы может предотвратить расширение переменной (интерполяция); %
экземпляры в командной строке, которые не являются частью ссылки на переменную, обрабатываются как литералы (например, 100%
).
Как правило, для безопасной работы со значениями переменных, которые могут содержать пробелы и специальные символы :
- Назначение : Заключить оба имя переменной и значение в одну пару двойных кавычек ; например,
set "v=a & b"
назначает буквенное значение a & b
переменной %v%
(напротив, set v="a & b"
сделает двойные кавычки частью значения). Escape литерал %
экземпляры как %%
(работает только в пакетных файлах - см. Выше). - Ссылка : Двойные кавычки ссылки на переменные , чтобы убедиться, что их значение не интерполировано; например,
echo "%v%"
не подвергает значение %v%
интерполяции и печатает "a & b"
(но учтите, что двойные кавычки тоже всегда печатаются). Напротив, echo %v%
передает литерал a
в echo
, интерпретирует &
как оператор последовательности команд и поэтому пытается выполнить команду с именем b
.
Также обратите внимание на приведенное выше предостережение относительно использования ^
с оператором call
.
- Внешние программы обычно заботятся об удалении заключенных в кавычки параметров, но, как отмечалось, в пакетных файлах вы должны сделать это самостоятельно (например,
%~1
, чтобы удалить заключающие в кавычки из 1-й параметр) и, к сожалению, я не знаю прямого способа получить echo
для точного вывода значения переменной без с двойными кавычками .
- Neil предлагает обходной путь на
for
, который работает , пока значение не имеет встроенных двойных кавычек ; e.g.:
set "var=^&')|;,%!"
for /f "delims=" %%v in ("%var%") do echo %%~v
cmd.exe
делает не распознает одинарные -цитаты как разделители строк - они рассматриваются как литералы и, как правило, не могут использоваться для разделения строк со встроенным пробелом; из этого также следует, что токены, примыкающие к одиночным кавычкам, и любые токены между ними рассматриваются как cmd.exe
как не заключенные в кавычки и интерпретируются соответствующим образом.
- Однако, учитывая, что целевые программы в конечном итоге выполняют собственный анализ аргументов, некоторые программы, такие как Ruby, распознают строки в одинарных кавычках даже в Windows; напротив, исполняемые файлы C / C ++, Perl и Python не распознают их.
Однако, даже если поддерживается целевой программой, не рекомендуется использовать строки в одинарных кавычках, поскольку их содержимое не защищено от потенциально нежелательной интерпретации cmd.exe
.
PowerShell
Windows PowerShell - намного более продвинутая оболочка, чем cmd.exe
, и она уже много лет входит в состав Windows (а PowerShell Core привел опыт PowerShell в macOS и Linux тоже).
PowerShell работает согласованно внутренне в отношении цитирования:
- внутри строк в двойных кавычках, используйте
`"
или ""
для экранирования двойных кавычек
- внутри строк в одинарных кавычках, используйте
''
для экранирования одинарных кавычек
Это работает в командной строке PowerShell и при передаче параметров в сценарии или функции PowerShell из в PowerShell.
(Как обсуждалось выше, для передачи экранированной двойной кавычки в PowerShell извне требуется \"
или, что более надежно, \""
- больше ничего не работает).
К сожалению, при вызове внешних программ вы сталкиваетесь с необходимостью применения собственных правил цитирования PowerShell и для выхода из цели программа:
Это проблемное поведение также обсуждается и обобщается в этом выпуске документации по GitHub
Двойные - кавычки внутри двойные - кавычки :
Рассмотрим строку "3`" of rain"
, которую PowerShell внутренне переводит в литерал 3" of rain
.
Если вы хотите передать эту строку во внешнюю программу, вы должны применить экранирование целевой программы , в дополнение к PowerShell; скажем, вы хотите передать строку программе на C, которая ожидает, что встроенные двойные кавычки будут экранированы как \"
:
foo.exe "3\`" of rain"
Обратите внимание, как и `"
- чтобы сделать PowerShell счастливым - и \
- чтобы сделать целевую программу счастливой - должны присутствовать.
Та же логика применяется для вызова командного файла, где необходимо использовать ""
:
foo.bat "3`"`" of rain"
В отличие от этого, для вставки одинарных кавычек в двойную строку в кавычках вообще не требуется экранирование.
Одиночные - кавычки внутри одинарные строки в кавычках do not требуют дополнительные экранирование; рассмотрим '2'' of snow'
, то есть представление PowerShell 2' of snow
.
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%
), которые расширены ; e.g.:
foo.exe --% "3\" of rain" -u %USERNAME%
Обратите внимание на то, что экранирования встроенного "
как \"
только для целевой программы (и не только для PowerShell, как \`"
) достаточно.
Однако этот подход:
- не позволяет экранировать
%
символов, чтобы избежать раскрытия переменных среды.
- исключает прямое использование переменных и выражений PowerShell; вместо этого командная строка должна быть встроена в строковую переменную на первом шаге, а затем вызываться с
Invoke-Expression
во втором.
Таким образом, несмотря на многочисленные усовершенствования, PowerShell не сильно облегчает экранирование при вызове внешних программ. Однако он ввел поддержку строк в одинарных кавычках.
Интересно, возможно ли в мире Windows когда-либо принципиально переключиться на модель Unix, позволяющую оболочке 1718 * делать весь токенизацию и удаление цитат предсказуемо , заранее? , независимо от целевой программы , а затем вызвать целевую программу, передав получившиеся токены.