1 (изменено: Rumata, 2015-03-29 19:34:04)

Тема: CMD/BAT: Возможность создания heredoc

Давно искал что-то подобное. В том смысле, что искал явно чужое и тыпался сделать что-то свое. В первом преуспел больше, а теперь пытаюсь компенсировать отсустствие второго некоторыми улучшениями первого.

Как говорит википедия:

Heredóc-синтаксис — способ определения строковых переменных в исходном коде программ
. . .
Heredoc-синтаксис позволяет определить строку, не заключая её в кавычки, в связи с чем необходимость экранирования этих символов отпадает.

Дословно, это возможность в тексте некоторой программы указать большой фрагмент произвольного текста внутри скрипта. Все более-менее продвинутые интерпретаторы имеют такие средства (за примерами предлагаю идти в гугл). А настоящем сообщении я поверду разговор о попытке внедрить heredoc в BAT/CMD файлы.

Исходные текст
Улучшение
-- перенаправление в файл в конце строки (пример закоммментирован)
-- допустимы любое количество пробельных символов-разделителей (пробел и табуляция)
-- более строгий синтаксис, но и в то же самое время более простой (при написании и чтении)


@echo off

set "hello=Hello world!"
set "lorem=Lorem ipsum dolor sit amet, consectetur adipiscing elit."

rem ( call :heredoc HTML & goto HTML ) >outerfile.txt
call :heredoc HTML & goto HTML
<html>
<title>!hello!</title>
<body>
<p>Variables in heredoc should be surrounded by the exclamation mark (^!).</p>
<p>!lorem!</p>
<p>Exclamation mark (^!) and caret (^^) MUST be escaped with a caret (^^).</p>
</body>
</html>
:HTML

goto :EOF

:: http://stackoverflow.com/a/15032476/3627676
:heredoc LABEL
setlocal enabledelayedexpansion
set go=
for /f "delims=" %%A in ( '
    findstr /n "^" "%~f0"
' ) do (
    set "line=%%A"
    set "line=!line:*:=!"

    if defined go (
        if "!line!" == "!go!" goto :EOF & goto :next2
        echo:!line!
    )

    rem Replace all TABs with SPACEs
    for /f "tokens=1,2,3,4,5 delims=():>& " %%i in ( "!line:    = !" ) do (
        if "%%i %%j %%k %%l" == "call heredoc %1 goto" (
            set "go=:%%m"
        )
    )
)
goto :EOF
( 2 * b ) || ! ( 2 * b )

2 (изменено: Rumata, 2015-06-04 12:13:28)

Re: CMD/BAT: Возможность создания heredoc

Обновление:


@echo off

set "hello=Hello world!"
set "lorem=Lorem ipsum dolor sit amet, consectetur adipiscing elit."

call :heredoc :HTML & goto :HTML
<html>
<title>!hello!</title>
<body>
<p>Variables in heredoc should be surrounded by the exclamation mark (^!).</p>
<p>!lorem!</p>
<p>Exclamation mark (^!) and caret (^^) MUST be escaped with a caret (^^).</p>
</body>
</html>
:HTML

goto :EOF

:: http://stackoverflow.com/a/15032476/3627676
:heredoc LABEL
setlocal enabledelayedexpansion
set go=
for /f "delims=" %%A in ( '
    findstr /n "^" "%~f0"
' ) do (
    set "line=%%A"
    set "line=!line:*:=!"

    if defined go (
        if "!line!" == "!go!" goto :EOF
        echo:!line!
    )

    rem Replace all TABs with SPACEs
    for /f "tokens=1,2,3,4,5 delims=():>&| " %%i in ( "!line:    = !" ) do (
        if "%%i %%j :%%k" == "call heredoc %1" set "go=:%%k"
        if "%%i %%j :%%k" == "call heredoc :%1" set "go=:%%k"
    )
)
goto :EOF

Упрощена проверка начала heredoc:
- важная команда теперь только call :heredoc LABEL, далее нет необходимости наличия goto LABEL, потому что с этого места можно перепрыгнуть на другу метку, конец сскрипта или вызвать команду exit /b
- удалил ненужную и лишнюю команду goto :next2
- можно писать как call :heredoc LABEL так и call :heredoc :LABEL

( 2 * b ) || ! ( 2 * b )

3 (изменено: wisgest, 2015-06-05 22:54:28)

Re: CMD/BAT: Возможность создания heredoc

    for /f "tokens=1-3 delims=()>&|    ,;= " %%i in ("!line!") do (
        if /i "%%i %%j %%k" == "call :heredoc %1" (
            set "go=%1"
            if not "!go:~,1!" == ":" set "go=:!go!"
        )
    )

1) из DELIMS исключено «:» — источник ложных срабатываний на команду закомментированную с помощью двоеточия или содержащую вызов не метки, а внешнего файла HEREDOC;
2) табуляция перенесена в DELIMS, после неё добавлены знаки «,;=», также воспринимаемые как разделители во внутренних командах;
3) добавлен ключ «/I».

4

Re: CMD/BAT: Возможность создания heredoc

wisgest, согласен. Так стало лучше:


@echo off

set "hello=Hello world!"
set "lorem=Lorem ipsum dolor sit amet, consectetur adipiscing elit."

call :heredoc HTML & goto :HTML
<html>
<title>!hello!</title>
<body>
<p>Variables in heredoc should be surrounded by the exclamation mark (^!).</p>
<p>!lorem!</p>
<p>Exclamation mark (^!) and caret (^^) MUST be escaped with a caret (^^).</p>
</body>
</html>
:HTML

goto :EOF

:: http://stackoverflow.com/a/15032476/3627676
:heredoc LABEL
setlocal enabledelayedexpansion
set go=
for /f "delims=" %%A in ( '
    findstr /n "^" "%~f0"
' ) do (
    set "line=%%A"
    set "line=!line:*:=!"

    if defined go (
        if /i "!line!" == "!go!" goto :EOF
        echo:!line!
    ) else (
        rem delims are ( ) > & | TAB , ; = SPACE
        for /f "tokens=1-3 delims=()>&|    ,;= " %%i in ( "!line!" ) do (
            if /i "%%i %%j %%k" == "call :heredoc %1" (
                set "go=%%k"
                if not "!go:~0,1!" == ":" set "go=:!go!"
            )
        )
    )
)
goto :EOF
( 2 * b ) || ! ( 2 * b )