Как мне заменить все двойные кавычки в параметрах моего пакетного файла на экранированные двойные кавычки? Это мой текущий пакетный файл, который раскрывает все параметры командной строки внутри строки:
@echo off
call bash --verbose -c "g++-linux-4.1 %*"
Затем он использует эту строку для вызова Cygwin bash, выполняя кросс-компилятор Linux. К сожалению, я получаю такие параметры, которые передаются в мой командный файл:
"launch-linux-g++.bat" -ftemplate-depth-128 -O3 -finline-functions
-Wno-inline -Wall -DNDEBUG -c
-o "C:\Users\Me\Documents\Testing\SparseLib\bin\Win32\LinuxRelease\hello.o"
"c:\Users\Me\Documents\Testing\SparseLib\SparseLib\hello.cpp"
Если первая кавычка вокруг первого переданного пути преждевременно завершает строку, передаваемую в GCC, а остальные параметры передаются непосредственно в bash (что очень неудачно).
Я предполагаю, что если я смогу объединить параметры в одну строку, а затем избежать кавычек, она должна работать нормально, но мне трудно определить, как это сделать. Кто-нибудь знает?
источник
^
является escape-символом только в строках без кавычек ; в строках, заключенных в двойные кавычки, он рассматривается как литерал. В отличие от оболочек Unix (POSIX-подобных), онcmd.exe
НЕ предлагает стандартизированной обработки оболочкой двойных кавычек внутри строки с двойными кавычками, а интерпретация предоставляется вызываемой программе (продолжение в следующем комментарии)."
символов. для экранирования\"
внутри строки с двойными кавычками (применяется как минимум к: C / C ++, Python, Perl, Ruby). С другой стороны,""
признаются только в меньшинстве случаев: В параметрах , передаваемых в пакетные файлы,""
будет признана в качестве встроенной двойной кавычки, но сохраняются как в соответствующем%<n>
параметре, даже после удаления ограждающих двойных кавычек с%~<n>
. Python любезно также признает""
в качестве альтернативы\"
.Собственный ответ eplawless просто и эффективно решает его конкретную проблему: он заменяет все
"
экземпляры во всем списке аргументов на\"
, как Bash требует представления двойных кавычек внутри строки с двойными кавычками.Чтобы в целом ответить на вопрос о том, как избежать двойных кавычек внутри строки с двойными кавычками, используйте
cmd.exe
интерпретатор командной строки Windows (будь то в командной строке - часто ошибочно называемой «подсказкой DOS» - или в командном файле): Смотрите внизу, чтобы посмотреть на PowerShell .tl; dr :
Вы должны использовать
""
при передаче строки в (другой) командный файл, и вы можете использовать""
с приложениями, созданными с помощью компиляторов Microsoft C / C ++ /. NET (которые также принимают\"
), которые в Windows включают Python и Node.js :Пример:
foo.bat "We had 3"" of rain."
Следующее относится только к пакетным файлам:
""
это единственный способ заставить интерпретатор команд (cmd.exe
) обрабатывать всю строку в двойных кавычках как один аргумент.К сожалению, однако, сохраняются не только закрывающие двойные кавычки (как обычно), но и двойные экранированные кавычки, поэтому получение предполагаемой строки представляет собой двухэтапный процесс; например, при условии , что двойные кавычки строка передается в качестве аргумента 1,
%1
:set "str=%~1"
удаляет заключительные двойные кавычки;set "str=%str:""="%"
затем преобразует двойные двойные кавычки в одинарные.Обязательно заключите части присваивания в двойные кавычки, чтобы предотвратить нежелательную интерпретацию значений.
\"
это требуется - как единственный вариант - многими другими программами , (! например, Ruby, Perl, и даже Microsoft собственный Windows PowerShell ()), но ЕГО ИСПОЛЬЗОВАНИЕ НЕ SAFE :\"
это то, что требуется многим исполняемым файлам и интерпретаторам, включая Windows PowerShell, при передаче строк извне - или, в случае компиляторов Microsoft, поддержка в качестве альтернативы""
- в конечном итоге, однако, целевая программа должна анализировать список аргументов .foo.exe "We had 3\" of rain."
\"
МОЖЕТ ПРИВЕСТИ К НЕЖЕЛАТЕЛЬНОМУ, ПРОИЗВОЛЬНОМУ ВЫПОЛНЕНИЮ КОМАНД и / или ПЕРЕПРАВКАМ ВХОДА / ВЫХОДА :& | < >
ver
команды; см. ниже объяснение и следующий пункт для обходного пути:foo.exe "3\" of snow" "& ver."
\""
и"^""
надежные, но ограниченные варианты (смотри раздел «Вызов CLI PowerShell в ...» ниже).Если вам необходимо использовать
\"
, есть только 3 безопасных подхода , которые, однако, довольно громоздки : Совет TS за его помощь.Используя (возможно, выборочное ) отложенное расширение переменной в вашем пакетном файле, вы можете сохранить литерал
\"
в переменной и ссылаться на эту переменную внутри"..."
строки с помощью!var!
синтаксиса - см . Полезный ответ TS .Только с БУКВАЛЬНЫМИ строками - те, которые НЕ включают ПЕРЕМЕННЫЕ - вы получаете аналогичный методический подход: категорически
^
-экранировать всеcmd.exe
метасимволы:" & | < >
и - если вы также хотите подавить расширение переменных -%
:foo.exe ^"3\^" of snow^" ^"^& ver.^"
В противном случае вы должны сформулировать свою строку на основе распознавания, какие части строки
cmd.exe
считаются некотируемыми из-за неправильной интерпретации\"
как закрывающие разделители:в буквальных частях, содержащих метасимволы оболочки: -
^
экранировать их; используя приведенный выше пример, это&
необходимо^
-экранировать:foo.exe "3\" of snow" "^& ver."
частями со
%...%
ссылками на переменные -style : убедитесь, что ониcmd.exe
считаются частью"..."
строки и что значения переменных сами по себе не имеют встроенных несбалансированных кавычек - что даже не всегда возможно .Для получения дополнительной информации читайте дальше.
Задний план
Примечание: это основано на моих собственных экспериментах. Дай мне знать, если я ошибаюсь.
POSIX-подобные оболочки, такие как Bash в Unix-подобных системах, токенизируют список аргументов (строку) перед передачей аргументов индивидуальной целевой программе: среди других расширений они разделяют список аргументов на отдельные слова (разделение слов) и удаляют символы кавычек из результирующие слова (удаление кавычек). Целевая программа вручено массив из отдельных аргументов , с синтаксическими цитаты удалены .
Напротив, интерпретатор команд Windows, по-видимому, не токенизирует список аргументов, а просто передает единственную строку, содержащую все аргументы, включая символы в кавычках. - в целевую программу.
Однако перед передачей в целевую программу одной строки выполняется некоторая предварительная обработка:
^
escape-символы. строки, не заключенные в двойные кавычки, удаляются (они экранируют следующий символ), а ссылки на переменные (например,%USERNAME%
) интерполируются первыми.Таким образом, в отличие от Unix, целевая программа несет ответственность за синтаксический анализ, чтобы проанализировать строку аргументов и разбить ее на отдельные аргументы с удаленными кавычками. Таким образом, для разных программ гипотетически могут потребоваться разные методы экранирования, и нет единого механизма экранирования, который гарантированно работал бы со всеми программами - https://stackoverflow.com/a/4094897/45375 содержит отличный фон по анархии, которая является командной строкой Windows парсинг.
На практике
\"
очень распространено, но НЕ БЕЗОПАСНО , как упоминалось выше:Так как
cmd.exe
сам по себе не признает\"
как бежала двойную кавычку, он может неправильно истолковать позже лексемы в командной строке, без кавычек и потенциально интерпретировать их как команду и / или ввод / вывод перенаправления .В двух словах: проблема поверхности, если любой из следующих символов следовать отверстию или несбалансированное
\"
:& | < >
; например:cmd.exe
видит следующие токены, полученные в результате неправильной интерпретации\"
как обычных двойных кавычек:"3\"
of
snow" "
& ver.
Так как
cmd.exe
считает , что& ver.
это не котировочные , он интерпретирует его как&
(оператор командной секвенировании), за которым следует имя команды для выполнения (ver.
-.
игнорируются;ver
отчетыcmd.exe
версии информации «ы).Общий эффект:
foo.exe
вызывается с первыми 3 токенами.ver
выполняется.Даже в тех случаях, когда случайная команда не причинит вреда, ваша общая команда не будет работать должным образом, поскольку ей передаются не все аргументы.
Многие компиляторы / интерпретаторы распознают ТОЛЬКО
\"
- например, компилятор GNU C / C ++, Python, Perl, Ruby, даже собственную оболочку Windows PowerShell от Microsoft при вызове изcmd.exe
- и, кроме (с ограничениями) для Windows PowerShell\""
, для них нет простого решения к этой проблеме.По сути, вам нужно заранее знать, какие части вашей командной строки неверно интерпретируются как не
^
заключенные в кавычки , и выборочно экранировать все экземпляры& | < >
в этих частях.Напротив, использование
""
БЕЗОПАСНО , но, к сожалению, поддерживается только исполняемыми файлами на основе компилятора Microsoft и пакетными файлами (в случае пакетных файлов с особенностями, описанными выше), что примечательно исключает PowerShell - см. Следующий раздел.Вызов интерфейса командной строки PowerShell из
cmd.exe
или POSIX-подобных оболочек:Примечание. В нижнем разделе показано, как цитирование обрабатывается внутри PowerShell.
При вызове извне - например, из
cmd.exe
командной строки или командного файла:PowerShell [Core] v6 + теперь правильно распознает
""
(в дополнение к\"
), что безопасно в использовании и сохраняет пробелы .pwsh -c " ""a & c"".length "
не ломается и правильно уступает6
Windows PowerShell (устаревшая версия, последняя версия которой - 5.1) распознает только
\"
and, в Windows также"""
и более надежный\""
/"^""
(хотя внутри PowerShell использует`
как escape-символ в строках с двойными кавычками, а также принимает""
- см. Нижний раздел):Вызов Windows PowerShell из
cmd.exe
командного файла:""
ломается , потому что принципиально не поддерживается:powershell -c " ""ab c"".length "
-> ошибка «В строке отсутствует терминатор»\"
и"""
работают в принципе , но небезопасно :powershell -c " \"ab c\".length "
работает по назначению: он выводит5
(обратите внимание на 2 пробела)cmd.exe
метасимволы нарушают команду, если не экранированы:powershell -c " \"a& c\".length "
breaks , из-за&
, которые должны быть экранированы как^&
\""
является безопасным , но нормализуют интерьер пробелы , которые могут быть нежелательными:powershell -c " \""a& c\"".length "
выводит4
(!), потому что 2 пробела нормализованы до 1."^""
это лучший выбор для Windows PowerShell конкретно , где она является безопасной и пробельным сохраняющим, но с PowerShell Ядром (на Windows) , это то же самое , как\""
, например, whitespace- нормализации . Заслуга 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-символ в строках без кавычек - внутри строк с двойными кавычками,^
не является специальным и обрабатывается как литерал.^
параметров in, переданных в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%%
. В командной строке%
нельзя экранировать, но если вы поместите a^
в начале, конце или внутри имени переменной в строке без кавычек (например,echo %^foo%
), вы можете предотвратить расширение переменной (интерполяцию);%
экземпляры в командной строке, которые не являются частью ссылки на переменную, обрабатываются как литералы (например,100%
).Как правило, для безопасной работы со значениями переменных, которые могут содержать пробелы и специальные символы :
set "v=a & b"
присваиваетa & b
переменной буквальное значение%v%
(наоборот,set v="a & b"
делает двойные кавычки частью значения). Экранировать%
экземпляры литералов как%%
(работает только в пакетных файлах - см. Выше).echo "%v%"
не подвергает значение%v%
интерполяции и печати"a & b"
(но обратите внимание, что двойные кавычки тоже неизменно печатаются). В противоположности этому ,echo %v%
передает буквальноеa
Toecho
, интерпретируют&
как оператор командную секвенировании, и поэтому пытается выполнить команду с именемb
.Также обратите внимание на приведенное выше предостережение о повторном использовании
^
сcall
заявлением.%~1
чтобы удалить заключительные двойные кавычки из 1-го параметра), и, к сожалению, нет прямого известный мне способecho
точной печати значения переменной без двойных кавычек .for
-На обходного пути , который работает до тех пор , пока значение не имеет встроенные двойные кавычки ; например:set "var=^&')|;,%!" for /f "delims=" %%v in ("%var%") do echo %%~v
cmd.exe
вовсе не признают одиночные -quotes , как разделители строк - они рассматриваются как литералы и обычно не могут быть использованы для определения строк с вложенными пробелами; кроме того, из этого следует, что токены, примыкающие к одинарным кавычкам, и любые токены между ними обрабатываются как не заключенные в кавычкиcmd.exe
и интерпретируются соответственно.Однако даже если это поддерживается целевой программой, не рекомендуется использовать строки в одинарных кавычках, поскольку их содержимое не защищено от потенциально нежелательной интерпретации с помощью
cmd.exe
.Цитата изнутри PowerShell:
Windows PowerShell - это гораздо более продвинутая оболочка, чем Windows
cmd.exe
, и она уже много лет является частью Windows (и PowerShell Core привнес возможности PowerShell в macOS и Linux).PowerShell внутренне согласованно работает с цитированием:
`"
или""
чтобы избежать двойных кавычек''
в одинарных кавычках используйте, чтобы избежать одинарных кавычекЭто работает в командной строке PowerShell и при передаче параметров в сценарии PowerShell или функции изнутри. PowerShell.
(Как обсуждалось выше, передача экранированных двойных кавычек в PowerShell извне требует
\"
или, что более надежно,\""
ничего не работает).К сожалению, при вызове внешних программ из PowerShell вы сталкиваетесь с необходимостью как учесть собственные правила цитирования PowerShell, так и уйти от целевой программы:
Это проблемное поведение также обсуждается и резюмируется в этом ответе.
Двойные кавычки внутри строк, заключенных в двойные кавычки :
Рассмотрим строку
"3`" of rain"
, которая внутри PowerShell переводится в буквальный3" of rain
.Если вы хотите передать эту строку во внешнюю программу, вы должны применить экранирование целевой программы в дополнение к PowerShell ; скажем, вы хотите передать строку программе C, которая ожидает, что встроенные двойные кавычки будут экранированы как
\"
:Обратите внимание, как должны присутствовать и то, и другое
`"
- чтобы сделать PowerShell счастливым, и\
- чтобы сделать целевую программу счастливой.Та же логика применяется к вызову командного файла, где
""
должны использоваться:Напротив, встраивание одинарных кавычек в строку с двойными кавычками вообще не требует экранирования.
Одиночное -quotes внутри отдельных -quoted строк ничего не требует дополнительного побега; рассмотрим
'2'' of snow'
, что является представлением PowerShell2' of snow
.PowerShell переводит строки с одинарными кавычками в двойные кавычки перед их передачей в целевую программу.
Однако двойные кавычки внутри одинарных кавычек , которые не нужно экранировать для PowerShell , все же нужно экранировать для целевой программы :
PowerShell v3 представил магический
--%
вариант , называемый стоп-разбор символом , который облегчает некоторые боли, пропускание ничего после того, как он необработанный к целевой программе, за исключениемcmd.exe
-Style среды переменной ссылки (например,%USERNAME%
), которые будут расширены; например:Обратите внимание, что экранирования встроенного кода
"
только\"
для целевой программы (а не для PowerShell as\`"
) достаточно.Однако такой подход:
%
символы, чтобы избежать раскрытия переменных среды.Invoke-Expression
помощью на втором.Таким образом, несмотря на многочисленные усовершенствования, PowerShell не упростил экранирование при вызове внешних программ. Тем не менее, он ввел поддержку строк в одинарных кавычках.
Интересно, возможно ли вообще в мире Windows когда-либо переключиться на модель Unix, позволяющую оболочке выполнять всю токенизацию и удаление цитат предсказуемо , заранее , независимо от целевой программы , а затем вызывать целевую программу, передавая полученные токены .
источник
Literal use of ^ in double-quoted strings can, be problematic when applying ~ ...
не совсем. Тильда удаляет только внешние кавычки, если они есть. Потеря каретки - это проблема самой обработки. Обычно этоset "param=%~1"
решает.~
- я обновил свой ответ, чтобы отразить мое новое понимание - прокомментируйте, если вы заметили проблему. Есть ли у вас объяснение того, что удвоение^
автоматически происходит при передаче параметров вcall
оператор?call echo cat^^&dog
это невозможно решить с помощью одного лишь количества вставок^
сcall
, который, как вы отмечаете, сильно нарушен. Кажется, что вcall echo cat^&dog
(single,^
который правильно экранирует&
) целевая команда (echo
) никогда даже не вызывается (!) - вся команда тихо терпит неудачу. Я обновил ответ соответственно.""
экранирование,"
но всегда\"
(см. Мой ответ, чтобы узнать о менее опасном способе его использования из cmd). Я не знаю , какой - либо официальной документации , которая определяет ,""
как сбежавший цитаты, но , по крайней мере , 2 в которых упоминается\"
: .NET и VS . Хотя это неверно задокументировано, Win32 api также следует этим правилам.В конце концов Google нашел ответ. Синтаксис пакетной замены строки следующий:
Что производит "реплицируй меня". Теперь мой сценарий выглядит так:
Который заменяет все экземпляры
"
с\"
, правильно сбежавшими для Баша.источник
В дополнение к отличному ответу mklement0 :
Почти все исполняемые файлы принимают
\"
как экранированные"
. Однако безопасное использование в cmd практически возможно только с помощью DELAYEDEXPANSION.Чтобы явно отправить литерал
"
какому-либо процессу, назначить\"
его переменной среды, а затем использовать эту переменную всякий раз, когда вам нужно передать цитату. Пример:Примечание,
SETLOCAL ENABLEDELAYEDEXPANSION
похоже, работает только в пакетных файлах. Чтобы получить ОТЛОЖЕННОЕ РАСШИРЕНИЕ в интерактивном сеансе, запуститеcmd /V:ON
.Если ваш пакетный файл не работает с DELAYEDEXPANSION, вы можете временно включить его:
Если вы хотите передать динамическое содержимое из переменной , которая содержит кавычки, которые ускользнули , как
""
вы можете заменить""
с\"
на расширение:Эта замена небезопасна при
%...%
расширении стиля!В случае OP
bash -c "g++-linux-4.1 !v_params:"=\"!"
- безопасная версия.Если по какой-то причине даже временное включение ОТЛОЖЕННОГО РАСШИРЕНИЯ невозможно, читайте дальше:
Использование
\"
изнутри cmd немного безопаснее, если нужно всегда избегать специальных символов, а не просто иногда. (Меньше вероятность забыть каретку, если она согласована ...)Для этого перед любой кавычкой ставится символ каретки (
^"
), кавычки, которые должны доходить до дочернего процесса в качестве литералов, должны дополнительно экранироваться с помощью обратной косой черты (\^"
). ВСЕ метасимволы оболочки также должны быть экранированы^
, например&
=>^&
;|
=>^|
;>
=>^>
; и т.п.Пример:
Источник: Все неправильно цитируют аргументы командной строки , см. «Лучший метод цитирования»
Для передачи динамического содержимого необходимо обеспечить следующее:
Часть команды, содержащая переменную, должна считаться "цитируемой"
cmd.exe
(это невозможно, если переменная может содержать кавычки - не пишите%var:""=\"%
). Для этого не выполняется экранирование последнего"
перед переменной и первого"
после переменной^
. cmd-метасимволы между этими двумя"
не должны экранироваться. Пример:Это небезопасно, если
%dynamic_content%
может содержать несогласованные кавычки.источник
^
исключение всех метасимволов работает надежно и может применяться более методично (но, очевидно, это королевская боль в выбранной вами части тела). Я соответственно обновил свой ответ (и отдал вам должное).!q!
способ). Примечание: Ваш ответ немного непоследователен после последнего редактирования: Рядом с верхними вы говорите: «Не не использовать^"
». Позже вы будете использовать^"
как часть обходного пути. Может быть, вы могли бы объяснить оба варианта? (1) Экранирование всех метасимволов (более методично) / (2) Выборочное экранирование метасимволов в "неfoo.exe ^"danger ^& bar=\"%dynamic_content%\"^"
заключенных в кавычки " областях (иногда необходимо для передачи динамического содержимого, например - таким образом переменная цитируется для cmd)\"
и""
. Я связался с вашим ответом за более сложный подход, основанный на переменных. Дайте мне знать, если теперь это имеет смысл.%dynamic_content%
в свой ответ. Как вы думаете, он достаточно подробный или мне нужно объяснять больше?setlocal delayedexpansion
, но вы должны закончить блокendlocal
(без аргумента). Честно говоря, у меня закружилась голова при взгляде на твой Гист. Здесь мы действительно имеем дело с крайними случаями, и я думаю, что будущие читатели найдут все, что им нужно, между нашими двумя ответами.Если строка уже заключена в кавычки, используйте другую кавычку, чтобы аннулировать ее действие.
источник
Например, для запуска инструмента автоматизации Unreal Engine из командного файла - это сработало для меня
например: -cmdline = "-Messaging" -device = device -addcmdline = "- SessionId = session -SessionOwner = 'owner' -SessionName = 'Build' -dataProviderMode = local -LogCmds = 'LogCommodity OFF' -execcmds = 'список автоматизации ; runtests tests + разделены + на + T1 + T2; quit '"-run
Надеюсь, это поможет кому-то, сработало для меня.
источник