Удаление двойных кавычек в пакетном режиме 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:

    • Пример: foo.bat "We had 3"" of rain."

    • Для пакетных файлов применяется только следующее:

      • "" - это единственный способ получить интерпретатор команд (cmd.exe) для обработки всей строки с двумя кавычками в качестве единственного аргумента.

      • Однако, к сожалению, сохраняются не только закрытые двойные кавычки (как обычно), но и удвоенные экранированные, поэтому получение намеченной строки является двухэтапным процессом; например, считая, что строка с двумя кавычками передается как первый аргумент, %1:

      • set "str=%~1" удаляет заключенные двойные кавычки; set "str=%str:""="%" затем преобразует двойные двойные кавычки в одиночные.
        Обязательно используйте закрытые двойные кавычки вокруг частей назначения, чтобы предотвратить нежелательную интерпретацию значений.

  • \" требуется - как единственный вариант - многими другими программами (например, 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

Надеюсь, это помогает кому-то, работал на меня.