2009-06-18 3 views
24

Есть ли способ указать многострочные строки в пакете таким же образом, как heredoc в Unix-оболочках. Нечто похожее на:heredoc для Windows пакет?

cat <<EOF > out.txt 
bla 
bla 
.. 
EOF 

Идея заключается в том, чтобы создать пользовательский файл из файла шаблона ..

ответ

25

Нет, насколько я знаю.

Ближайший я знаю это

> out.txt (
    @echo.bla 
    @echo.bla 
    ... 
) 

(@ предотвращает саму командную оболочку из печати команды он работает, и echo. позволяет начать строку с пробелом.)

+5

Есть ли решение для передачи контента другой команде? –

+0

Вы можете передать другую команду, см. Мой пост ниже. Однако кредит относится к «эфемерным» для лучшей техники. –

17

Да, очень возможно.^- буквальный escape-символ, просто поставьте его перед вашей новой строкой. В этом примере, я поставил дополнительный символ новой строки, как хорошо, так что он правильно печататься в файле:

@echo off 
echo foo^

this is^

a multiline^

echo > out.txt 

Выход:

E:\>type out.txt 
foo 
this is 
a multiline 
echo 

E:\> 
0

Это еще проще, и близко напоминает кота < < EOF > out.txt:

C: \> copy con out.txt
Это моя первая строка текста.
Это моя последняя строка текста.
^ Z
1 файл скопирован.

Выход выглядит следующим образом:

C: \> тип out.txt
Это моя первая строка текста.
Это моя последняя строка текста.

(копия кон + out.txt введите свой вклад, а затем Ctrl-Z и файл копируется)

COPY CON означает "копия консоли" (ввод данных пользователем)

+4

это будет работать с консоли, но как насчет внутри пакетного файла? – Amro

1

В Microsoft NMake makefile можно использовать true UNIX heredocs, поскольку владелец потока запросил их. Например, это явное правило для создания файла Deploy.sed:

Deploy.sed: 
    type << >[email protected] 
; -*-ini-generic-*- 
; 
; Deploy.sed -- Self-Extracting Directives 
; 

[Version] 
Class=IEXPRESS 
SEDVersion=3 
    . 
    . 
[Strings] 
InstallPrompt=Install $(NAME)-$(VERSION).xll to your personal XLSTART directory? 
DisplayLicense=H:\prj\prog\XLL\$(NAME)\README.txt 
    . 
    . 
<< 

clean: 
    -erase /Q Deploy.sed 

где < < расширяется в имя временного файла NMake создает на лету при выполнении правила. То есть, когда Deploy.sed не существует. Приятно, что переменные NMake также расширены (здесь переменные ИМЯ и ВЕРСИЯ). Сохраните это как makefile.Откройте DOS-окно в каталоге Makefile и использования:

> nmake Deploy.sed 

для создания файла, а также:

> nmake clean 

, чтобы удалить его. NMake является частью всех версий Visual Studio C++, включая Express-выпуски.

+0

+1 Я всегда хотел узнать NMake. Это сильно отличается от обычного GNU Make (у меня есть Cygwin и MinGW)? – Amro

+0

Это 20 + лет, и мне кажется, Microsoft не развила его гораздо дальше, так как они отказались от экспорта make-файлов из Visual Studio. С другой стороны, GNU стал довольно совершенным и мощным. Makefile - это отличный инструмент для работы в командной строке. Зачастую они могут заменять командные скрипты/командные команды. Я использую make-файлы на любой платформе; на Windows Cygwin GNU make и NMake. Я благодарен, что они по-прежнему поставляют его с этим GUI-замком Visual Studio 2010. –

+0

Я думаю, что он был заменен на основе XML [MSBuild] (http://en.wikipedia.org/wiki/MSBuild) – Amro

2

Вы можете создать цитируемый блок текста с циклом FOR/F, поэтому вам не нужно было бежать от специальных символов, таких как <>|&, только % должны быть экранированы.
Это иногда полезно, например, создание html-вывода.

@echo off 
setlocal EnableDelayedExpansion 
set LF=^ 


REM Two empty lines are required 
set ^"NL=^^^%LF%%LF%^%LF%%LF%^^" 

for /F "tokens=* delims=_" %%a in (^"%NL% 
___"One<>&|"%NL% 
___"two 100%%"%NL% 
___%NL% 
___"three "quoted" "%NL% 
___"four"%NL% 
") DO (
    @echo(%%~a 
) 

Выход

One<>&| 
two 100% 

three "quoted" 
four 

Я пытаюсь объяснить код. Переменная LF содержит один символ новой строки, переменная NL содержит ^<LF><LF>^.
Это можно использовать с процентом расширения, чтобы разместить символ ОДНА символ новой строки и один карет на конце строки.

Обычно FOR/F разделяет цитируемый текст на несколько токенов, но только один раз.
Когда я вставляю символы новой строки, цикл FOR также разбивается на несколько строк.
Цитата в первой и последней строке предназначена только для создания правильного синтаксиса для цикла FOR.

В начале любой строки находятся _, так как первый символ будет экранирован из многострочной каретки предыдущей строки, и если котировка является первым символом, она теряет способность к побегу.
Используются лимиты _, поскольку пробелы или запятые вызывают проблемы с XP (Else XP-Bug ложный пытается получить доступ к файлам мусора).

Каретка на конце линии также относится только к XP-Bug.

XP-Bug приходит в действие, когда цитируемый текст содержит некотируемые ,;=<space> символы

for /f "tokens=*" %%a in ("a","b","c") do echo %%a 
+0

+1 спасибо. Мне тяжело после этого, дальнейшее объяснение было бы весьма полезно. – Amro

9
@echo off 
for /f "delims=:" %%a in (
    'findstr -n "^___" %0') do set "Line=%%a" 

(for /f "skip=%Line% tokens=* eol=_" %%a in (
     'type %0') do echo(%%a) > out.html 
:: out.html 
pause 
goto: EOF 



___DATA___ 
<!Doctype html> 
<html> 
    <head> 
    title></title> 
    </head> 
    <body> 
    <svg width="900" height="600"> 
     <text x="230" 
       y="150" 
       font-size="100" 
       fill="blue" 
       stroke="gray" 
       stroke-width="1"> 
        Hello World    
     </text> 
    </svg> 
    </body> 
</html> 
+0

Это отличное начало. Посмотрите http://stackoverflow.com/q/7885437/745412 для получения дополнительной информации о том, как это сделать. – Jared

+0

Удивительно, это сработало отлично для меня! Единственное, что я должен был сделать, это добавить 'SETLOCAL DISABLEDELAYEDEXPANSION' перед циклом' for' (в моем выходном файле отсутствовали восклицательные знаки из-за того, что раньше было включено замедленное расширение). Он по-прежнему удаляет пробелы в начале строк в выходном файле, но я возьму его. – Shoelaced

3

@jeb

setlocal EnableDelayedExpansion 
set LF=^ 


REM Two empty lines are required 

другой вариант:

@echo off 

:) 
setlocal enabledelayedexpansion 
>nul,(pause&set /p LF=&pause&set /p LF=)<%0 
set LF=!LF:~0,1! 

echo 1!LF!2!LF!3 

pause 
+0

+1, очень приятно видеть альтернативный способ создания LF и эффект команды паузы – jeb

2
@echo off 
cls 
title Drop Bomb 
echo/ 
echo/ creating... 
::         Creating a batchfile from within a batchfile. 
echo @echo off > boom.bat 
echo cls  >> boom.bat 
echo color F0 >> boom.bat 
echo echo/ >> boom.bat 
echo echo --- B-O-O-M !!! --- >> boom.bat 
echo echo/ >> boom.bat 
echo pause >> boom.bat 
echo exit  >> boom.bat 
::          Now lets set it off 
start boom.bat 
title That hurt my ears. 
cls 
echo/ 
echo - now look what you've done! 
pause 
+0

(спасибо Justin) – InterociterOperator

24

Вот еще один подход.

@echo off 

:: ###################################################### 
:: ## Heredoc syntax:         ## 
:: ## call :heredoc uniqueIDX [>outfile] && goto label ## 
:: ## contents           ## 
:: ## contents           ## 
:: ## contents           ## 
:: ## etc.            ## 
:: ## :label           ## 
:: ##             ## 
:: ## Notes:           ## 
:: ## Variables to be evaluated within the heredoc  ## 
:: ## should be called in the delayed expansion style ## 
:: ## (!var! rather than %var%, for instance).   ## 
:: ##             ## 
:: ## Literal exclamation marks (!) and carats (^)  ## 
:: ## must be escaped with a carat (^).    ## 
:: ###################################################### 



:-------------------------------------------- 
: calling heredoc with results sent to stdout 
:-------------------------------------------- 

call :heredoc stickman && goto next1 

\o/ 
| This is the "stickman" heredoc, echoed to stdout. 
/\ 
:next1 



:----------------------------------------------------------------- 
: calling heredoc containing vars with results sent to a text file 
:----------------------------------------------------------------- 

set bodyText=Hello world! 
set lipsum=Lorem ipsum dolor sit amet, consectetur adipiscing elit. 

call :heredoc html >out.txt && goto next2 
<html lang="en"> 
    <body> 
     <h3>!bodyText!</h3> 
     <p>!lipsum!</p> 
    </body> 
</html> 

Thus endeth the heredoc. :) 
:next2 



echo; 
echo Does the redirect to a file work? Press any key to type out.txt and find out. 
echo; 

pause>NUL 
type out.txt 
del out.txt 

:: End of main script 
goto :EOF 

:: ######################################## 
:: ## Here's the heredoc processing code ## 
:: ######################################## 
:heredoc <uniqueIDX> 
setlocal enabledelayedexpansion 
set go= 
for /f "delims=" %%A in ('findstr /n "^" "%~f0"') do (
    set "line=%%A" && set "line=!line:*:=!" 
    if defined go (if #!line:~1!==#!go::=! (goto :EOF) else echo(!line!) 
    if "!line:~0,13!"=="call :heredoc" (
     for /f "tokens=3 delims=>^ " %%i in ("!line!") do (
      if #%%i==#%1 (
       for /f "tokens=2 delims=&" %%I in ("!line!") do (
        for /f "tokens=2" %%x in ("%%I") do set "go=%%x" 
       ) 
      ) 
     ) 
    ) 
) 
goto :EOF 

Пример вывода:

C:\Users\oithelp\Desktop>heredoc 

\o/ 
| This is the "stickman" heredoc, echoed to stdout. 
/\ 

Does the redirect to a file work? Press any key to type out.txt and find out. 

<html lang="en"> 
    <body> 
     <h3>Hello world!</h3> 
     <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p> 
    </body> 
</html> 

Thus endeth the heredoc. :) 
+0

приятно. спасибо за обмен – Amro

+2

+1, Два небольших улучшения. используйте 'echo (' вместо 'echo;' иначе он терпит неудачу с линией, содержащей '/?'. Разделите номер строки с помощью 'set 'line =! line: *: =!" ', как и с delims =: вы удаляете также все ведущие двоеточия – jeb

+0

Спасибо jeb. Реализовано – rojo

0

Что ОП хотел было что-то очень специфичны (создание текстового файла с выходом) и принятый ответ делает это отлично, но решение, представленное не хорошо работают вне этого конкретного контекста. Например, если я хочу передать многострочный ввод в команду, я не могу использовать синтаксис (echo).Вот что заработало для меня.

Учитывая сценарий Perl под названием "echolines.pl", состоящий из (для имитации программы 'реальной') следующей:

use strict; 
use warnings; 

while (<>) { 
     chomp; 
     print qq(<$_>\n); 
} 

и пакетный файл с именем "testme.bat", содержащий:

@echo off 

set FOO=foo 
set BAR=bar 
set BAZ=baz 

echo %FOO%^ 
&echo %BAR%^ 
&echo %BAZ%|perl echolines.pl 

работает она производит ожидаемый результат:

C:\>testme 
<foo> 
<bar> 
<baz> 

Care с пробелами должны быть приняты для ванной убедитесь, что все работает правильно, без каких-либо пробелов. В частности: каждый конец строки должен быть кареткой (^), за которой следует новая строка, последующие строки должны начинаться немедленно с амперсанда (&), а последняя строка должна иметь канал, начинающийся сразу после последнего отправленного элемента. В противном случае это приведет к отсутствию параметров или дополнительных пробелов до и после параметров.

4

Использование в macro with parameters позволяет писать «Heredoc» более простым способом:

@echo off 

rem Definition of heredoc macro 
setlocal DisableDelayedExpansion 
set LF=^ 


::Above 2 blank lines are required - do not remove 
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^" 
set heredoc=for %%n in (1 2) do if %%n==2 (%\n% 
     for /F "tokens=1,2" %%a in ("!argv!") do (%\n% 
      if "%%b" equ "" (call :heredoc %%a) else call :heredoc %%a^>%%b%\n% 
      endlocal ^& goto %%a%\n% 
     )%\n% 
    ) else setlocal EnableDelayedExpansion ^& set argv= 


rem Heredoc syntax: 
rem 
rem %%heredoc%% :uniqueLabel [outfile] 
rem contents 
rem contents 
rem ... 
rem :uniqueLabel 
rem 
rem Same notes of rojo's answer apply 

rem Example borrowed from rojo's answer: 

set bodyText=Hello world! 
set lipsum=Lorem ipsum dolor sit amet, consectetur adipiscing elit. 

%heredoc% :endHtml out.txt 
<html lang="en"> 
    <body> 
     <h3>!bodyText!</h3> 
     <p>!lipsum!</p> 
    </body> 
</html> 
:endHtml 

echo File created: 
type out.txt 
del out.txt 
goto :EOF 


rem Definition of heredoc subroutine 

:heredoc label 
set "skip=" 
for /F "delims=:" %%a in ('findstr /N "%1" "%~F0"') do (
    if not defined skip (set skip=%%a) else set /A lines=%%a-skip-1 
) 
for /F "skip=%skip% delims=" %%a in ('findstr /N "^" "%~F0"') do (
    set "line=%%a" 
    echo(!line:*:=! 
    set /A lines-=1 
    if !lines! == 0 exit /B 
) 
exit /B 
3

Ссылаясь на пост Рохо по адресу https://stackoverflow.com/a/15032476/3627676

Определенно, его решение является то, что я ищу немного времени (конечно, я мог бы попытаться реализовать что-то подобное, но лень движется вперед :)). Одна вещь, которую я хотел бы добавить, - незначительное улучшение исходного кода. Я думал, что было бы лучше, если бы перенаправление на файл было написано в конце строки. В этом случае стартовая линия 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 

:: https://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 

Что я предлагаю с помощью этого кода? Давайте рассмотрим.

код Rojo является очень строгим:

  • не позволяет более чем один пробел символ в строке между call и :heredoc
  • call :heredoc липкий к краю линии (нет каких-либо пробелы не допускается в начало строки)
  • перенаправление в файл разрешено где-то в пределах линии (не очень полезно) -

Вещи я предлагаю:

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

Обновление 1: Усовершенствования проверки и выполнения в начале Heredoc:

  • Важная команда - call :heredoc LABEL или call :heredoc :LABEL.Поэтому после печати содержимого heredoc можно перейти на другую метку, конец скрипта или запустить exit /b.
  • удалены неиспользуемые и ненужные команды Гото: Next2

Обновление 2:

  • Разделители для внутреннего for( являются )>&|TAB,;=SPACE
  • Переключатель /I добавлен в if

Update 3:

По следующей ссылке вы можете найти полную версию автономного сценария (встраивание в сценариях имеется) https://github.com/ildar-shaimordanov/tea-set/blob/master/bin/heredoc.bat

5

Более на DosTips, siberia-man опубликовал демонстрацию amazing behavior of an erroneous GOTO statement в форме (goto) 2>nul. Затем Аачини и Джеб задокументировали некоторые дополнительные интересные открытия о странном поведении. Он в основном ведет себя как EXIT /B, за исключением того, что он позволяет выполнять конкатенированные команды в подпрограмме CALLed в контексте родительского вызывающего.

Вот краткий сценарий, который демонстрирует большинство важных моментов:

@echo off 
setlocal enableDelayedExpansion 
set "var=Parent Value" 
(
    call :test 
    echo This and the following line are not executed 
    exit /b 
) 
:break 
echo How did I get here^^!^^!^^!^^! 
exit /b 

:test 
setlocal disableDelayedExpansion 
set "var=Child Value" 
(goto) 2>nul & echo var=!var! & goto :break 
echo This line is not executed 

:break 
echo This line is not executed 

- ВЫВОД -

var=Parent Value 
How did I get here!!!! 

Это удивительное поведение позволил мне написать элегантную пакетную эмуляцию здесь doc со многими вариантами, доступными для unix. Я реализовал PrintHere.bat как отдельную утилиту, которую нужно поместить в папку, указанную в вашем PATH. Тогда любой пакетный скрипт может легко вызвать программу, чтобы получить здесь функциональность doc.

Вот общий синтаксис использования:

call PrintHere :Label 
Here doc text goes here 
:Label 

Как это возможно достичь ... Моя утилита PrintHere использует (GOTO) 2>nul трюк дважды.

  • В первый раз я использую (GOTO) 2>nul, чтобы вернуться к абоненту, так что я могу получить полный путь к сценарию вызова, так что PrintHere знает, что файл для чтения. Затем я ВЫЗЫВАЮТ PrintHere второй раз!

  • Во второй раз я использую (GOTO) 2>nul, чтобы вернуть вызывающему абоненту и GOTO завершающую метку, чтобы текст этого документа не был выполнен.

Примечания - сценарий ниже содержит символ табуляции (0x09) в определении вкладки, непосредственно под :start этикетки. Некоторые браузеры могут испытывать трудности при отображении и копировании вкладки. В качестве альтернативы вы можете download PrintHere.bat.txt from my dropbox и просто переименуйте его в PrintHere.bat.

Я изначально размещен PrintHere.bat at DosTips, где вы можете отслеживать будущее развитие.

PrintHere.bat

@echo off & setlocal disableDelayedExpansion & goto :start 
::PrintHere.bat version 1.1 by Dave Benham 
::: 
:::call PrintHere [/E] [/- "TrimList"] :Label ["%~f0"] 
:::call PrintHere [/E] [/- "TrimList"] :Label "%~f0" | someCommand & goto :Label 
:::PrintHere /? 
:::PrintHere /V 
::: 
::: PrintHere.bat provides functionality similar to the unix here doc feature. 
::: It prints all content between the CALL PrintHere :Label line and the 
::: terminating :Label. The :Label must be a valid label supported by GOTO, with 
::: the additional constraint that it not contain *. Lines are printed verbatim, 
::: with the following exceptions and limitations: 
::: 
::: - Lines are lmited to 1021 bytes long 
::: - Trailing control characters are stripped from each line 
::: 
::: The code should look something like the following: 
::: 
:::  call PrintHere :Label 
:::   Spacing and blank lines are preserved 
::: 
:::  Special characters like & < > |^! % are printed normally 
:::  :Label 
::: 
::: If the /E option is used, then variables between exclamation points are 
::: expanded, and ! and^literals must be escaped as ^! and ^^. The limitations 
::: are different when /E is used: 
::: 
::: - Lines are limited to ~8191 bytes long 
::: - All characters are preserved, except !variables! are expanded and ^! and 
:::  ^^ are transformed into ! and^
::: 
::: Here is an example using /E: 
::: 
:::  call PrintHere /E :SubstituteExample 
:::  Hello !username!^! 
:::  :SubstituteExample 
::: 
::: If the /- "TrimList" option is used, then leading "TrimList" characters 
::: are trimmed from the output. The trim characters are case sensitive, and 
::: cannot include a quote. If "TrimList" includes a space, then it must 
::: be the last character in the list. 
::: 
::: Multiple PrintHere blocks may be defined within one script, but each 
::: :Label must be unique within the file. 
::: 
::: PrintHere must not be used within a parenthesized code block. 
::: 
::: Scripts that use PrintHere must use \r\n for line termination, and all lines 
::: output by PrintHere will be terminated by \r\n. 
::: 
::: All redirection associated with a PrintHere must appear at the end of the 
::: command. Also, the CALL can include path information: 
::: 
:::  call "c:\utilities\PrintHere.bat" :MyBlock>test.txt 
:::  This line is written to test.txt 
:::  :MyBlock 
::: 
::: PrintHere may be used with a pipe, but only on the left side, and only 
::: if the source script is included as a 2nd argument, and the right side must 
::: explicitly and unconditionally GOTO the terminating :Label. 
::: 
:::  call PrintHere :PipedBlock "%~f0" | more & goto :PipedBlock 
:::  text goes here 
:::  :PipedBlock 
::: 
::: Commands concatenated after PrintHere are ignored. For example: 
::: 
:::  call PrintHere :ignoreConcatenatedCommands & echo This ECHO is ignored 
:::  text goes here 
:::  :ignoreConcatenatedCommands 
::: 
::: PrintHere uses FINDSTR to locate the text block by looking for the 
::: CALL PRINTHERE :LABEL line. The search string length is severely limited 
::: on XP. To minimize the risk of PrintHere failure when running on XP, it is 
::: recommended that PrintHere.bat be placed in a folder included within PATH 
::: so that the utility can be called without path information. 
::: 
::: PrintHere /? prints out this documentation. 
::: 
::: PrintHere /V prints out the version information 
::: 
::: PrintHere.bat was written by Dave Benham. Devlopment history may be traced at: 
::: http://www.dostips.com/forum/viewtopic.php?f=3&t=6537 
::: 

:start 
set "tab= " NOTE: This value must be a single tab (0x09), not one or more spaces 
set "sp=[ %tab%=,;]" 
set "sp+=%sp%%sp%*" 
set "opt=" 
set "/E=" 
set "/-=" 

:getOptions 
if "%~1" equ "" call :exitErr Invalid call to PrintHere - Missing :Label argument 
if "%~1" equ "/?" (
    for /f "tokens=* delims=:" %%L in ('findstr "^:::" "%~f0"') do echo(%%L 
    exit /b 0 
) 
if /i "%~1" equ "/V" (
    for /f "tokens=* delims=:" %%L in ('findstr /rc:"^::PrintHere\.bat version" "%~f0"') do echo(%%L 
    exit /b 0 
) 
if /i %1 equ /E (
    set "/E=1" 
    set "opt=%sp+%.*" 
    shift /1 
    goto :getOptions 
) 
if /i %1 equ /- (
    set "/-=%~2" 
    set "opt=%sp+%.*" 
    shift /1 
    shift /1 
    goto :getOptions 
) 
echo %1|findstr "^:[^:]" >nul || call :exitErr Invalid PrintHere :Label 
if "%~2" equ "" (
    (goto) 2>nul 
    setlocal enableDelayedExpansion 
    if "!!" equ "" (
    endlocal 
    call %0 %* "%%~f0" 
) else (
    >&2 echo ERROR: PrintHere must be used within a batch script. 
    (call) 
) 
) 
set ^"call=%0^" 
set ^"label=%1^" 
set "src=%~2" 
setlocal enableDelayedExpansion 
set "call=!call:\=[\\]!" 
set "label=!label:\=[\\]!" 
for %%C in (. [ $ ^^ ^") do (
    set "call=!call:%%C=\%%C!" 
    set "label=!label:%%C=\%%C!" 
) 
set "search=!sp!*call!sp+!!call!!opt!!sp+!!label!" 
set "cnt=" 
for /f "delims=:" %%N in ('findstr /brinc:"!search!$" /c:"!search![<>|&!sp:~1!" "!src!"') do if not defined skip set "skip=%%N" 
if not defined skip call :exitErr Unable to locate CALL PrintHere %1 
for /f "delims=:" %%N in ('findstr /brinc:"!sp!*!label!$" /c:"!sp!*!label!!sp!" "!src!"') do if %%N gtr %skip% if not defined cnt set /a cnt=%%N-skip-1 
if not defined cnt call :exitErr PrintHere end label %1 not found 
if defined /E (
    for /f "skip=%skip% delims=" %%L in ('findstr /n "^^" "!src!"') do (
    if !cnt! leq 0 goto :break 
    set "ln=%%L" 
    if not defined /- (echo(!ln:*:=!) else for /f "tokens=1* delims=%/-%" %%A in (^""%/-%!ln:*:=!") do (
     setlocal disableDelayedExpansion 
     echo(%%B 
     endlocal 
    ) 
    set /a cnt-=1 
) 
) else (
    for /l %%N in (1 1 %skip%) do set /p "ln=" 
    for /l %%N in (1 1 %cnt%) do (
    set "ln=" 
    set /p "ln=" 
    if not defined /- (echo(!ln!) else for /f "tokens=1* delims=%/-%" %%A in (^""%/-%!ln!") do (
     setlocal disableDelayedExpansion 
     echo(%%B 
     endlocal 
    ) 
) 
) <"!src!" 
:break 
(goto) 2>nul & goto %~1 


:exitErr 
>&2 echo ERROR: %* 
(goto) 2>nul & exit /b 1 

Полная документация вложена в сценарии. Ниже приведены некоторые демонстрации использования:

дословное выходного

@echo off 
call PrintHere :verbatim 
    Hello !username!^! 
    It is !time! on !date!. 
:verbatim 

- ВЫХОД -

Hello !username!^! 
    It is !time! on !date!. 


Развернуть переменные (задержка расширения не должна быть включена)

@echo off 
call PrintHere /E :Expand 
    Hello !username!^! 
    It is !time! on !date!. 
:Expand 

--OUTPUT--

Hello Dave! 
    It is 20:08:15.35 on Fri 07/03/2015. 


Расширить переменные и подрезания ведущие пробелы

@echo off 
call PrintHere /E /- " " :Expand 
    Hello !username!^! 
    It is !time! on !date!. 
:Expand 

--OUTPUT--

Hello Dave! 
It is 20:10:46.09 on Fri 07/03/2015. 


Выход может быть перенаправлен в файл

@echo off 
call PrintHere :label >helloWorld.bat 
    @echo Hello world! 
:label 


Выход не может быть перенаправлен как ввод, но он может быть поданным по трубопроводу! К сожалению, синтаксис не так изящен, потому что both sides of a pipe are executed in a new CMD.EXE process, поэтому (GOTO) 2>nul возвращается к дочернему процессу cmd, а не мастер-скрипту.

@echo off 
call PrintHere :label "%~f0" | findstr "^" & goto :label 
    Text content goes here 
:label 
+0

очень интересно, спасибо. Я не эксперт по партии, поэтому я допускаю, что большая часть этого - это над моей головой;) – Amro

+0

@Amro - Возможно, слишком сложно понять, как это работает, но вы не должны понять это, чтобы использовать его ;-) Я разработал утилиту для удобства нас е. – dbenham

+0

Если вы хотите доставить одну летучую мышь, содержащую PrintHere вместе с основным скриптом, будет ли она работать с использованием помеченных вызовов, то есть 'call: PrintHere: endLabel'? –

-4
C:\>more >file.txt 
This is line 1 of file 
This is line 2 of file 
^C 

C:\>type file.txt 
This is line 1 of file 
This is line 2 of file 

** Это добавит пустую строку в конце, но вы можете решить, что легко, просто с помощью метода копирования мошенника:

C:\>copy con file.txt >nul 
This is line 1 of file 
This is line 2 of file^Z 

C:\>type file.txt 
This is line 1 of file 
This is line 2 of file 

Берегись, где вы вводите^C и^Z в каждом случае.

+4

У меня может быть что-то не хватает, но я не вижу, как это отвечает на вопрос. Если да, уточните. – blm

0

Попробуйте этот код. (JScript код на дне пишет «out.html» на диск)

@if(0)==(0) echo on 
cscript.exe //nologo //E:JScript "%~f0" source1 out.html 
start out.html 
goto :EOF 

[source1] 
<!DOCTYPE html> 
<html> 
    <head> 
    title></title> 
    </head> 
    <body> 
    <svg width="900" height="600"> 
     <text x="230" 
       y="150" 
       font-size="100" 
       fill="blue" 
       stroke="gray" 
       stroke-width="1"> 
        Hello World    
     </text> 
    </svg> 
    </body> 
</html> 
[/source1] 

@end 

if (WScript.Arguments.length != 2) WScript.Quit(); 
var tagName = WScript.Arguments(0); 
var path = WScript.Arguments(1); 
var startTag = "[" + tagName + "]" 
var endTag = "[/" + tagName + "]" 
var fso = new ActiveXObject("Scripting.FileSystemObject"); 
var file1 = fso.OpenTextFile(WScript.ScriptFullName); 
var txt = ""; 
var found = false; 
while (!file1.AtEndOfStream) { 
    var line = file1.ReadLine(); 
    if (!found) { 
    if (line.lastIndexOf(startTag, 0) === 0) found = true; 
    } else { 
    if (line.lastIndexOf(endTag, 0) === 0) break; 
    txt += line + "\n"; 
    } 
} 
file1.Close(); 
var file2 = fso.CreateTextFile(path, true, false); 
file2.Write(txt); 
file2.Close(); 
0

Вот вариант отличного решения ephemient в.Это позволяет трубы нескольких линий в другую программу без фактического создания текстового файла и ввода переадресован в программе:

(@echo.bla 
@echo.bla 
) | yourprog.exe 

Для быстрого, рабочего примера, вы можете заменить yourprog.exe с more:

(@echo.bla 
@echo.bla 
) | more 

Выход:

bla 
bla 
1

Расширение на ephemient пост, который я чувствую себя лучше, следующий будет делать трубы:

(
    @echo.line1 
    @echo.line2 %time% %os% 
    @echo. 
    @echo.line4 
) | more 

В пост ephemient, он перенаправляется в начале, что хороший стиль, но вы также можете перенаправить в конце, как например:

(
    @echo.line1 
    @echo.line2 %time% %os% 
    @echo. 
    @echo.line4 
) >C:\Temp\test.txt 

Обратите внимание, что «@ECHO.» никогда не включается в выход и «@echo». сама по себе дает пустую строку.