heredoc para o lote do Windows?

Existe uma maneira de especificar strings de múltiplas linhas em lote de maneira similar a heredoc em shells unix. Algo parecido com:

cat < out.txt bla bla .. EOF 

A idéia é criar um arquivo personalizado a partir de um arquivo de modelo.

Não tão longe quanto o que sei.

O mais próximo que eu sei é

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

( @ impede que o próprio shell de comando imprima os comandos que estão sendo executados e echo. permite iniciar uma linha com um espaço.)

Aqui está outra abordagem.

 @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   

!bodyText!

!lipsum!

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 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

Exemplo de saída:

 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.   

Hello world!

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Thus endeth the heredoc. :)

Sim, muito possivel. ^ é o caractere de escape literal, basta colocá-lo antes de sua nova linha. Neste exemplo, eu coloco a nova linha adicional também para que ela seja impressa corretamente no arquivo:

 @echo off echo foo ^ this is ^ a multiline ^ echo > out.txt 

Saída:

 E:\>type out.txt foo this is a multiline echo E:\> 
 @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>   title>     Hello World     

Na DosTips, o siberia-man postou uma demonstração de comportamento surpreendente de uma declaração GOTO errônea na forma de (goto) 2>nul . Aacini e jeb então documentaram algumas descobertas interessantes adicionais sobre o comportamento estranho. Ele basicamente se comporta como um EXIT /B , exceto que permite que comandos concatenados dentro de uma rotina CALL sejam executados no contexto do chamador pai.

Aqui está um breve roteiro que demonstra a maioria dos pontos principais:

 @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 

– SAÍDA –

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

Esse comportamento incrível me permitiu escrever uma emulação de lote elegante de um documento aqui com muitas das opções disponíveis para unix. Implementei PrintHere.bat como um utilitário autônomo que deve ser colocado em uma pasta listada em seu PATH. Então, qualquer script em lote pode facilmente chamar o utilitário para obter a funcionalidade doc.

Aqui está a syntax geral de uso:

 call PrintHere :Label Here doc text goes here :Label 

Como isso pode ser conseguido? … Meu utilitário PrintHere usa o truque (GOTO) 2>nul duas vezes.

  • A primeira vez que uso (GOTO) 2>nul para retornar ao chamador para que eu possa obter o caminho completo para o script de chamada para que o PrintHere saiba de qual arquivo ler. Eu então chamo PrintHere uma segunda vez!

  • A segunda vez que eu uso (GOTO) 2>nul para retornar ao chamador e GOTO a etiqueta de terminação para que o texto doc aqui não seja executado.

Nota – o script abaixo contém um caractere de tabulação (0x09) na definição da guia, diretamente abaixo do :start label :start . Alguns navegadores podem ter dificuldade em exibir e copiar a guia. Como alternativa, você pode baixar o PrintHere.bat.txt da minha checkbox de depósito e simplesmente renomeá-lo para PrintHere.bat.

Originalmente postei PrintHere.bat no DosTips , onde você pode acompanhar o desenvolvimento futuro.

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 

A documentação completa está incorporada no script. Abaixo estão algumas demonstrações de uso:

Saída versátil

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

– SAÍDA –

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

Expandir variables ​​(a expansão atrasada não precisa estar ativada)

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

–SAÍDA–

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

Expandir variables ​​e aparar espaços à esquerda

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

–SAÍDA–

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

Saída pode ser redirecionada para um arquivo

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

A saída não pode ser redirecionada como input, mas pode ser canalizada! Infelizmente, a syntax não é tão elegante porque ambos os lados de um pipe são executados em um novo processo CMD.EXE , portanto, (GOTO) 2>nul retorna para um processo cmd filho, e não para o script mestre.

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

O uso de uma macro com parâmetros permite escrever um “heredoc” de maneira mais simples:

 @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   

!bodyText!

!lipsum!

: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

@jeb

 setlocal EnableDelayedExpansion set LF=^ REM Two empty lines are required 

outra variante:

 @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 

Referindo-se ao post do rojo em https://stackoverflow.com/a/15032476/3627676

Definitivamente, sua solução é o que eu estou procurando há pouco tempo (claro, eu poderia tentar implementar algo semelhante a isso, mas a preguiça move o progresso :)). Uma coisa que gostaria de acrescentar é uma pequena melhoria no código original. Eu pensei que seria melhor se o redirecionamento para o arquivo fosse escrito no final da linha. Neste caso, a linha de partida heredoc poderia ser mais rigorosa e sua análise mais simples.

 @echo off set "hello=Hello world!" set "lorem=Lorem ipsum dolor sit amet, consectetur adipiscing elit." call :heredoc HTML & goto :HTML  !hello!  

Variables in heredoc should be surrounded by the exclamation mark (^!).

!lorem!

Exclamation mark (^!) and caret (^^) MUST be escaped with a caret (^^).

: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

O que estou sugerindo por este código? Vamos considerar.

O código do Rojo é muito estrito:

  • não permite mais de um caractere de espaço em branco na cadeia entre a call e :heredoc
  • call :heredoc é pegajosa até a borda da linha (sem espaços em branco permitidos no início da linha)
  • redirecionamento para o arquivo é permitido em algum lugar dentro da linha (não muito útil) –

Coisas que estou sugerindo:

  • menos rigoroso (mais de um espaço em branco como delimitadores)
  • o redirecionamento para o arquivo é permitido somente no final da linha (colchetes arredondados são permitidos e necessários)
  • nenhum código pegajoso na borda da linha

Atualização 1 : Melhorias na verificação e execução do início do heredoc:

  • Importante comando é somente call :heredoc LABEL ou call :heredoc :LABEL . Então, depois de imprimir o conteúdo heredoc, é possível pular para outro label, fim do script ou executar exit /b .
  • removeu o comando não utilizado e desnecessário goto: next2

Atualização 2 :

  • Delimitadores para interior são ( ) > & | TAB ; = SPACE
  • O interruptor /I adicionei a if

Atualização 3 :

Pelo seguinte link você pode encontrar a versão completa do script autônomo (incorporação em seus scripts está disponível) https://github.com/ildar-shaimordanov/tea-set/blob/master/bin/heredoc.bat

Você pode criar um bloco de texto entre aspas com um loop FOR / F, então você não precisa escaping de caracteres especiais como <>|& % só tem que ser escapado.
Isso às vezes é útil como criar uma saída 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 ) 

Saída

 One<>&| two 100% three "quoted" four 

Eu tento explicar o código. A variável LF contém um caractere de nova linha, a variável NL contém ^^ .
Isso pode ser usado com a expansão percentual para colocar um caractere de nova linha e um acento circunflexo no final da linha.

Normalmente, um FOR / F divide um texto entre aspas em vários tokens, mas apenas uma vez.
Ao inserir caracteres de nova linha, o loop FOR também se divide em várias linhas.
As citações na primeira e na última linha são apenas para criar a syntax correta para o loop FOR.

Na frente de qualquer linha são _ como o primeiro caractere será escapado do cursor de várias linhas da linha anterior, e se a citação for o primeiro caractere, ele perde a capacidade de escape.
Os delims são usados, pois espaços ou vírgulas causam problemas com o XP (caso contrário, o XP-Bug tenta acessar nomes de arquivos inválidos).

O cursor no final da linha também é apenas contra o XP-Bug.

O XP-Bug entra em vigor quando um texto citado contém caracteres não-marcados ,;=

 for /f "tokens=*" %%a in ("a","b","c") do echo %%a 
 @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 --- BOOM !!! --- >> 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 

Em um makefile do Microsoft NMake, é possível usar true heredocs do UNIX , conforme solicitado pelo proprietário do encadeamento. Por exemplo, esta é uma regra explícita para criar um arquivo Deploy.sed :

 Deploy.sed: type < < >$@ ; -*-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 

onde < < expande para um nome de arquivo temporário que o NMake cria dinamicamente ao executar a regra. Ou seja, quando Deploy.sed não existe. O bom é que as variables ​​NMake também são expandidas (aqui as variables NAME e VERSION ). Salve isso como makefile . Abra uma checkbox DOS no diretório de makefile e use:

 > nmake Deploy.sed 

para criar o arquivo e:

 > nmake clean 

para removê-lo. O NMake faz parte de todas as versões do Visual Studio C ++, incluindo as edições Express.

Expandindo o post do ephemient, que eu acho que é o melhor, o seguinte irá fazer um pipe:

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

No post do ephemient ele redirecionou no começo, o que é um estilo legal, mas você também pode redirect no final como tal:

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

Observe que “@echo” nunca é incluído na saída e “@echo”. por si só dá uma linha em branco.

Isto é ainda mais fácil, e se assemelha a cat < < EOF> out.txt:

C: \> copy con out.txt
Esta é minha primeira linha de texto.
Esta é minha última linha de texto.
^ Z
1 arquivo (s) copiado (s).

Saída parece com isso:

C: \> digite out.txt
Esta é minha primeira linha de texto.
Esta é minha última linha de texto.

(copie con + out.txt, digite sua input, seguida por Ctrl-Z e o arquivo é copiado)

COPY CON significa “copiar do console” (aceitar input do usuário)

O que o OP queria era algo muito específico (criar um arquivo de texto com a saída) e a resposta aceita faz isso perfeitamente, mas a solução apresentada não funciona bem fora desse contexto específico. Por exemplo, se eu quiser passar a input de várias linhas em um comando, não posso usar a syntax ( echo ) . Aqui está o que acabou funcionando para mim.

Dado um script em perl chamado “echolines.pl”, que consiste no seguinte (para simular um programa ‘real’):

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

e um arquivo de lote chamado “testme.bat” contendo:

 @echo off set FOO=foo set BAR=bar set BAZ=baz echo %FOO%^ &echo %BAR%^ &echo %BAZ%|perl echolines.pl 

a execução produz a saída esperada:

 C:\>testme    

Cuidados com os espaços em branco devem ser tomados para garantir que tudo funcione corretamente, sem espaços perdidos em qualquer lugar. Especificamente: cada final de linha deve ser um acento circunflexo (^) seguido por uma nova linha, as linhas subseqüentes devem começar imediatamente com oe comercial (&) e a última linha deve ter o encadeamento começando imediatamente após o último item a ser enviado. Não fazer isso resultará em parâmetros ausentes ou espaços em branco extras antes e depois dos parâmetros.

Tente este código. (O código JScript na parte inferior escreve “out.html” no disco)

 @if(0)==(0) echo on cscript.exe //nologo //E:JScript "%~f0" source1 out.html start out.html goto :EOF [source1] < !DOCTYPE html>   title>     Hello World     [/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(); 

Aqui está uma variante da excelente solução do efêmero. Isso permite canalizar várias linhas em outro programa sem realmente criar um arquivo de texto e redirecioná-lo para o seu programa:

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

Para um exemplo rápido e funcional, você pode replace o yourprog.exe por more :

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

Saída:

 bla bla 
 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 

** Ele adicionará uma linha vazia no final, mas você pode resolver isso facilmente, apenas usando o método copy con:

 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 

Cuidado com o que você digita ^ C e ^ Z em cada caso.