Как разделить двойную кавычку на несколько строк в пакетном файле Windows?

Длинные команды в командных файлах Windows можно разделить на несколько строк, используя ^, как указано в Длинные команды, разделенные на несколько строк в пакетном (.bat) файле Windows Vista.

Однако, если каретка находится внутри строки с двойными кавычками, она не будет работать. Например:

echo "A very long line I want to ^
split into two lines"

Это напечатает "A very long line I want to ^ и скажет мне, что split - неизвестная команда.

Есть ли способ обойти это?

Ответ 1

Я вижу три возможных обходных пути.

1) Построение линии, объединяющей несколько параметров.

@echo off
SETLOCAL EnableDelayedExpansion

set "line="
for %%a in ("line1" 
"line2"
"line3"
"line4"
) do set line=!line!%%~a
echo !line!

2) Оставляя "цитату" в конце каждой строки

@echo on
SETLOCAL EnableDelayedExpansion

set "line=line1 & x#"^
 "line2 & a#"^
 "line3 & b #"^
 "line4 & c "

set "line=!line:#" "=!"
echo !line!

Первое место в каждой строке важно, потому что каретка работает как многострочный символ, но также ускользает от первого символа, поэтому также будет скрыта цитата.
Поэтому я заменяю unnessary # "" после построения строки.

EDIT Добавлено: 3) Исчезающие кавычки

setlocal EnableDelayedExpansion
echo "A very long line I want to !"=!^
split into two lines"

По-моему, это лучший способ, он работает, когда синтаксический анализатор сначала видит кавычки, и поэтому последний карет будет работать, поскольку он, кажется, находится вне кавычек.
Но это выражение !"=! будет расширять переменную с именем "=, но такое имя переменной не может существовать (знак равенства может появляться только как первый символ), поэтому он расширяется до нуля.

Вы также можете создавать безопасные выражения, они всегда будут избегать кавычек, независимо, если в строке есть цитата или нет.
!"^"=!

echo This multiline works !"^"=!^
as expected
echo "This multiline works !"^"=!^
too"

Если вы хотите избежать замедленного расширения, вы также можете использовать -FOR-Loop, например

for %%^" in ("") do (
echo "This multiline works %%~"^
too"
)

Ответ 2

Самый прямой ответ - это избежать котировок. Они будут напечатаны, но они не будут функционально указывать содержимое до CMD.EXE.

@echo off
echo ^"A very long line I want to ^
split into two lines^"

Любые специальные символы, которые появляются в строке, также должны быть экранированы, поскольку они больше не функционально цитируются.

@echo off
echo ^"A very long line I want to ^
split into two lines ^
that also contains special characters ^^ ^& ^| ^> ^< ^"

Как сказал Джеб, продолжение строки ускользает от первого символа следующей строки. Поэтому, если первый символ следующей строки является особым символом, его нельзя избегать во второй раз. В приведенном ниже коде будут приведены те же результаты, что и в предыдущем примере.

@echo off
echo ^"A very long line I want to ^
split into two lines ^
that also contains special characters ^^ ^
& ^| ^> ^< ^"

Ответ 3

Я придумал свой собственный метод для этого сегодня, и я никогда не видел, чтобы это предложило где-либо, поэтому я решил опубликовать его здесь. Конечно, это не элегантно в объективном смысле. Я бы сказал, что у него есть свой уникальный уродливый вид и некоторые ограничения, но я считаю его гораздо более "эргономичным" по сравнению с альтернативами.

В частности, этот метод обладает уникальной характеристикой: ему не нужно ничего избегать, но при этом выполняется типичная замена переменных. Это позволяет мне взять некоторую строку, которая выглядит именно так, как я хочу, распределить ее по нескольким строкам и добавить префикс к каждой строке, не изменяя ничего в строке. Таким образом, не требуется метод проб и ошибок, чтобы выяснить, как могут взаимодействовать специальные символы и escape-символы. В целом, я думаю, что это уменьшает когнитивную нагрузку, необходимую для детерминированного создания сложной строковой переменной на нескольких строках, что хорошо для меня, потому что я не хочу задумываться и расстраиваться из-за случайной сложности, такой как нюансы команды windows переводчик. Кроме того, похожая техника может быть использована в Linux Bash, что делает его несколько портативным.

Примечание: я не проверял это полностью, он может не работать для некоторых случаев использования, я не знаю. Тем не менее, в примере есть довольно много, казалось бы, проблемных символов, и он работает, поэтому он выглядит несколько надежным.

set IMAGE_NAME=android-arm64
set CMD=docker run --rm
set CMD=%CMD% --platform=linux
set CMD=%CMD% -v %CD%:/work
set CMD=%CMD% dockcross/%IMAGE_NAME%
set CMD=%CMD% /bin/sh -c
set CMD=%CMD% "mkdir build-%IMAGE_NAME% &&
set CMD=%CMD% cd build-%IMAGE_NAME% &&
set CMD=%CMD% cmake .. &&
set CMD=%CMD% cmake --build ."

echo %CMD%

В моем случае это команда, поэтому я могу запустить ее с помощью:

%CMD%

Я буду открыт для любых отзывов или предложений об этом методе. Возможно, это даже можно улучшить.

Ответ 4

Очевидное преимущество метода @solvingJ по сравнению с вариантами Jeb состоит в том, что совершенно очевидно, что происходит, и что в левой части есть пространственное разделение уродливого содержимого cmd, а справа - фактическое содержимое. И это может быть улучшено в удобочитаемости, помещая больше места между левой и правой частью:

set      CMD=   docker run --rm
set CMD=%CMD%     --platform=linux
set CMD=%CMD%     -v %CD%:/work
set CMD=%CMD%     dockcross/%IMAGE_NAME%
set CMD=%CMD%     /bin/sh -c
set CMD=%CMD%       "mkdir build-%IMAGE_NAME% &&
set CMD=%CMD%       cd build-%IMAGE_NAME% &&
set CMD=%CMD%       cmake .. &&
set CMD=%CMD%       cmake --build ."

К сожалению, это невозможно продемонстрировать в комментарии, потому что несколько пробелов уменьшены до одного. Поэтому я делаю в ответе то, что на самом деле является просто комментарием к ответу @solvingJ, который я считаю лучшим.

Ответ 5

Если вы хотите добавить пустые строки, убедитесь, что у вас есть пробел ДО ^ во 2-й строке

эхо Привет, мир ^  ^ Хорошего дня !