Удаление двойных кавычек в пакетном режиме Script
Как мне пойти на замену всех двойных кавычек в моих параметрах пакетного файла с помощью экранированных двойных кавычек? Это мой текущий командный файл, который расширяет все параметры командной строки внутри строки:
@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 (что не срабатывает эффектно.)
Я предполагаю, что если я смогу конкатенировать параметры в одну строку, а затем убежать от кавычек, она должна работать нормально, но мне сложно определить, как это сделать. Кто-нибудь знает?
Ответы
Ответ 1
Google в итоге придумал ответ. Синтаксис для замены строки в пакете таков:
set v_myvar=replace me
set v_myvar=%v_myvar:ace=icate%
Что производит "репликация меня". Мой script теперь выглядит следующим образом:
@echo off
set v_params=%*
set v_params=%v_params:"=\"%
call bash -c "g++-linux-4.1 %v_params%"
Который заменяет все экземпляры "
на \"
, правильно экранировался для bash.
Ответ 2
Эквивалентный символ в пакетных сценариях ^
. Но для строк с двойными кавычками удвоьте кавычки:
"string with an embedded "" character"
Ответ 3
беззаботный собственный ответ просто и эффективно решает его конкретную проблему: он заменяет все "
экземпляры во всем списке аргументов с помощью \"
, так как Bash требует двойных кавычек внутри строки с двумя кавычками.
Чтобы ответить на вопрос о том, как избежать двойных кавычек внутри строки с двумя кавычками, используя cmd.exe
, интерпретатор командной строки Windows (как в командной строке, часто по-прежнему ошибочно называемый "подсказкой DOS", так и в партии файл): см. ниже, чтобы посмотреть PowerShell.
tl; dr:
-
Вы должны использовать ""
при передаче строки в (ругой) пакетный файл, и вы можете использовать ""
с приложениями, созданными с Microsoft C/C++/.NET компиляторов (которые также принимают \"
), который в Windows, включает в себя Python и Node.js:
-
\"
требуется - как единственный вариант - многими другими программами (например, Ruby, Perl и даже Microsoft - PowerShell (!)), но ЕГО ИСПОЛЬЗОВАНИЕ НЕ БЕЗОПАСНО:
-
\"
- это то, что требуется многим исполняемым файлам и интерпретаторам - включая Microsoft PowerShell при передаче строк извне - или, в случае компиляторов Microsoft, поддержка в качестве альтернативы ""
- в конечном счете, однако, это до целевой программы для проанализируйте список аргументов. - Пример:
foo.exe "We had 3\" of rain."
- ОДНАКО, ИСПОЛЬЗОВАНИЕ
\"
МОЖЕТ ПРИВЕСТИ К НЕСОВЕРШЕННОМУ, АРБИТРАЖНОМУ ИСПОЛНЕНИЮ КОМАНД И/ИЛИ ВХОДА/ВЫХОДОВ: - Следующие символы представляют этот риск:
& | < >
& | < >
- Например, следующие результаты в непреднамеренном выполнении команды
ver
; см. ниже ниже для пояснения и следующего пункта для обходного пути: -
foo.exe "3\" of snow" "& ver."
- Для PowerShell только для Windows,
\""
является надежной альтернативой.
-
Если вы должны использовать \"
, есть только 3 безопасных подхода, которые, однако, довольно громоздки: Совет шляпы в TS для его помощи.
-
Используя (возможно, выборочное) замедленное расширение переменной в вашем командном файле, вы можете сохранить литерал \"
в переменной и ссылаться на эту переменную внутри строки "..."
используя синтаксис !var!
- см. Полезный ответ TS.
- Вышеупомянутый подход, несмотря на громоздкость, имеет то преимущество, что вы можете применять его методично и что он работает надежно, с любым вводом.
-
Только с ЛИТЕРАЛЬНЫМИ строками, не связанными с ПЕРЕМЕННЫМИ, вы получаете аналогичный методический подход: категорически ^
-escape все метасимволы cmd.exe
: " & | < >
и - если вы также хотите подавить переменное расширение - %
:
foo.exe ^"3\^" of snow^" ^"^& ver.^"
-
В противном случае вы должны сформулировать свою строку на основе распознавания того, какие части строки cmd.exe
считаются неупорядоченными из-за неправильного толкования \"
качестве закрывающих разделителей:
-
в буквальных частях, содержащих метасимволы оболочки: ^
-escape; используя пример выше, это &
должно быть ^
-escape d:
foo.exe "3\" of snow" "^& ver."
-
по частям с ссылками на %...%
-style: убедитесь, что cmd.exe
считает их частью строки "..."
и что значения переменных сами не имеют встроенных несбалансированных котировок, что даже не всегда возможно.
Для получения справочной информации прочитайте.
Фон
Примечание. Это основано на моих собственных экспериментах.Дайте мне знать, если я ошибаюсь.
POSIX-подобные оболочки, такие как Bash на Unix-подобных системах, блокируют список аргументов (строку) перед передачей аргументов индивидуально в целевую программу: среди других расширений они разбивают список аргументов на отдельные слова (разбиение слов) и удаляют цитирующие символы из результирующие слова (удаление цитат). Целевая программа передается концептуально массивом отдельных аргументов с (синтаксически-обязательными) кавычками.
Напротив, интерпретатор команд Windows, по-видимому, не ликвидирует список аргументов и просто передает единственную строку, содержащую все аргументы, включая кавычки символов. - в целевую программу.
Однако некоторая предварительная обработка выполняется до того, как одна целая строка будет передана целевой программе: ^
escape-символы. вне строк с двойными кавычками удаляются (они избегают следующего символа), а сначала ссылаются ссылки на переменные (например, %USERNAME%
).
Таким образом, в отличие от Unix, ответственность за целевую программу заключается в том, чтобы проанализировать строку аргументов и разбить ее на отдельные аргументы с удалением кавычек. Таким образом, разные программы могут гипотетически требовать разных методов экранирования и нет единого механизма экранирования, который гарантированно работает со всеми программами. fooobar.com/questions/4522/... содержит отличный фон анархии, которая является командной строкой 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, даже Microsoft, принадлежащий PowerShell при вызове из cmd.exe
- и, кроме PowerShell с \""
, для них там не является простым решением этой проблемы.
По сути, вам нужно заранее знать, какие части вашей командной строки неверно истолковываются как некорректные, и выборочно ^
-escape все экземпляры & | < >
& | < >
в этих частях.
Напротив, использование ""
SAFE, но, к сожалению, поддерживается только исполняемыми и командами файлов -c ompiler -based (в случае пакетных файлов с описанными выше причудами).
В отличие от этого, PowerShell при вызове извне - например, из cmd.exe
, будь то из командной строки или командного файла - распознает только \"
и, в Windows, более надежный \""
, хотя внутренне PowerShell использует '
как escape-символ в двойных кавычках, а также принимает ""
, например:
-
powershell -c " \"ab c\".length"
works (выходы 4
), также как и более надежные
powershell -c " \""ab c\"".length"
,
-
но powershell -c " ""ab c"".length"
breaks.
Связанная информация
-
^
может использоваться только как 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.
-
К сожалению, исключение литерала %
- это особый случай, который требует четкого синтаксиса в зависимости от того, указана ли строка в командной строке и внутри командного файла; см. fooobar.com/questions/93489/...
- Короче: внутри командного файла используйте
%%
. В командной строке %
не может быть экранировано, но если вы поместите a ^
в начале, в конце или внутри имени переменной в некотируемой строке (например, echo %^foo%
), вы можете предотвратить расширение переменной (интерполяцию); %
экземпляров в командной строке, которые не являются частью ссылки на переменные, рассматриваются как литералы (например, 100%
).
-
Как правило, чтобы безопасно работать с переменными значениями, которые могут содержать пробелы и специальные символы:
- Назначение: укажите как имя переменной, так и значение в одной паре двойных кавычек; например,
set "v=a & b"
присваивает буквенное значение a & b
переменной %v%
(напротив, set v="a & b"
сделает двойную кавычку части значения). Исключить литерал %
экземпляров как %%
(работает только в пакетных файлах - см. Выше). - Ссылка: ссылки на двойные кавычки, чтобы убедиться, что их значение не интерполировано; например,
echo "%v%"
не подвергает значение %v%
интерполяции и выводит "a & b"
(но обратите внимание, что двойные кавычки также напечатаны). Напротив, echo %v%
передает литерал a
для echo
, интерпретирует &
как оператор последовательности команд и поэтому пытается выполнить команду с именем b
.
Также обратите внимание на приведенное выше предостережение в использовании ^
с оператором call
. - Внешние программы обычно заботятся о том, чтобы удалять закрытые двойные кавычки вокруг параметров, но, как отмечено, в пакетных файлах вы должны делать это самостоятельно (например,
%~1
для удаления закрытых двойных кавычек из первого параметра) и, к сожалению, там не является прямым способом, который я знаю, чтобы получить echo
чтобы напечатать переменное значение точно без заключенных двойных кавычек. - Neil предлагает обходное решение
for
-based, которое работает до тех пор, пока значение не имеет встроенных двойных кавычек; например:
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"
Напротив, вложение одиночных кавычек в строку с двумя кавычками не требует никакого экранирования.
Одиночные кавычки внутри строк с одним кавычком не требуют дополнительного ускорения; рассмотрим '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 была введена опция magic --%
, называемая символом остановки-синтаксического анализа, которая облегчает часть боли, передавая что-либо после того, как она не интерпретируется целевой программой, за исключением ссылок на переменные среды cmd.exe
-style (например, %USERNAME%
), которые расширены; например:
foo.exe --% "3\" of rain" -u %USERNAME%
Обратите внимание на то, что достаточно избегать встроенных "
как \"
для целевой программы (а также не для PowerShell как \'"
).
Однако такой подход:
- не позволяет избегать
%
символов, чтобы избежать разложений переменных среды. - исключает прямое использование переменных и выражений PowerShell; вместо этого командная строка должна быть построена в строковой переменной на первом шаге, а затем вызываться с
Invoke-Expression
за секунду.
Таким образом, несмотря на множество достижений, PowerShell не ускользнул при вызове внешних программ. Тем не менее, он ввел поддержку для строк с одной кавычкой.
Интересно, возможно ли вообще в мире Windows когда-либо переключиться на Unix-модель, позволяющую оболочке делать все условные обозначения и цитаты изначально предсказуемыми, независимо от целевой программы, а затем вызывать целевую программу, передавая итоговые токены,
Ответ 4
В дополнение к mklement0 отличный ответ:
Почти все исполняемые файлы принимают \"
как экранированный "
. Безопасное использование в cmd, однако, практически возможно только с помощью DELAYEDEXPANSION.
Чтобы явным образом отправить литерал "
для какого-то процесса, назначить \"
переменной среды, а затем использовать эту переменную, всякий раз, когда вам нужно передать цитату. Пример:
SETLOCAL ENABLEDELAYEDEXPANSION
set q=\"
child "malicious argument!q!&whoami"
Примечание. SETLOCAL ENABLEDELAYEDEXPANSION
работает только в пакетных файлах. Чтобы получить DELAYEDEXPANSION в интерактивном сеансе, запустите cmd/V:ON
.
Если ваш пакетный файл не работает с DELAYEDEXPANSION, вы можете временно включить его:
::region without DELAYEDEXPANSION
SETLOCAL ENABLEDELAYEDEXPANSION
::region with DELAYEDEXPANSION
set q=\"
echoarg.exe "ab !q! & echo danger"
ENDLOCAL
::region without DELAYEDEXPANSION
Если вы хотите передать динамический контент из переменной, содержащей кавычки, которые выбраны как ""
вы можете заменить ""
на \"
при расширении:
SETLOCAL ENABLEDELAYEDEXPANSION
foo.exe "danger & bar=region with !dynamic_content:""=\"! & danger"
ENDLOCAL
Эта замена небезопасна при расширении %...%
!
В случае OP bash -c "g++-linux-4.1 !v_params:"=\"!"
это безопасная версия.
Если по какой-либо причине даже временное включение DELAYEDEXPANSION не является опцией, прочитайте:
Использование \"
изнутри cmd немного безопаснее, если вам всегда нужно избегать специальных символов, а не просто иногда. (Это менее вероятно, чтобы забыть каретку, если она последовательна...)
Для достижения этой цели предшествует любая цитата с каретой (^"
), кавычки, которые должны достигнуть дочернего процесса, поскольку литералы должны дополнительно экранироваться с помощью люфта (\^"
). ВСЕ метасимволы оболочки должны быть экранированы с помощью ^
а, например, &
=> ^&
; |
=> ^|
; >
=> ^>
; и т.п.
Пример:
child ^"malicious argument\^"^&whoami^"
Источник: все цитируют неверные аргументы командной строки, см. "Лучший метод цитирования",
Чтобы передать динамический контент, необходимо обеспечить следующее:
Часть команды, которая содержит переменную, должна считаться "цитируемой" cmd.exe
(это невозможно, если переменная может содержать кавычки - не писать %var:""=\"%
). Для этого последняя "
перед переменной, а первый "
после переменной не ^
-escaped. CMD-метасимволы между этими двумя "
не должны быть экранированы. Пример:
foo.exe ^"danger ^& bar=\"region with %dynamic_content% & danger\"^"
Это небезопасно, если %dynamic_content%
может содержать непревзойденные кавычки.
Ответ 5
Например, для инструмента Unreal Engine Automation запускается из пакетного файла - это сработало для меня
например: -cmdline = "-Messaging" -device = устройство -addcmdline = "-SessionId = сеанс -SessionOwner = 'владелец' -SessionName = 'Build' -dataProviderMode = local -LogCmds = ' LogCommodity OFF '-execcmds =' список автоматизации, тесты runtests + разделенные + + T1 + T2; quit '"-run
Надеюсь, это помогает кому-то, работал на меня.