Как пакетный скрипт может сделать эквивалент "cat << eof"? - PullRequest
4 голосов
/ 31 октября 2011

В Linux (Bash) есть очень полезная функциональность для выгрузки литерального текста в другой файл, подобный этому:

cat > see.txt << EOF
contents going into
my file
EOF

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

call:catMyChunk myCustomText c:\see.txt
exit /b

goto:myCustomText
   This is my test file
   Hope you like it.

    <got these>
    % and these %
    ! these too

   yeah
:myCustomText

:catMyChunk
    ::Should call this function with 2 args, MYDELIM and outFile.txt
    ::where is to be catted to outFile.txt
    ::and text starts with <beginning of line>goto:MYDELIM
    ::and ends with <beginning of line>:MYDELIM
    set searchStart=goto:%~1
    set searchStop=:%~1
    set outFile=%~2
    set startLine=0
    set endLine=0
    for /f "delims=:" %%a in ('findstr -b -n !searchStart! %~dpnx0') do set "startLine=%%a"
    for /f "delims=:" %%a in ('findstr -b -n !searchStop!  %~dpnx0') do set "endLine=%%a"

    set /a linesLeftToRead=%endLine% - %startLine%
    del %outFile%
    if "%linesLeftToRead%" LEQ "0" (
        echo Error finding start and end delmieters for %searchStop% in catMyChunk routine
        exit /B 1
    )
    setlocal DisableDelayedExpansion
    for /f "usebackq skip=%startLine% delims=" %%a in (`"findstr /n ^^ %~dpnx0"`) do (
        set "oneLine=%%a"
        setlocal EnableDelayedExpansion
        set "oneLine=!oneLine:*:=!"
        set /a linesLeftToRead-=1
        if !linesLeftToRead! LEQ 0 exit /B
        echo(!oneLine!>>%outFile%
    )

goto: EOF

Таким образом, мое требование состоит в том, чтобы фрагмент текста выводился буквально без каких-либо изменений (т. Е. Я не хочу избегать пустых строк,%,!, <И т. Д.). Этот код выполняет почти все, что мне нужно, за исключением того, что я не нашел способа правильно вывести восклицательные знаки. Вот вывод, который я получаю, что не совсем верно: </p>

   This is my test file
   Hope you like it.

    <got these>
    % and these %
     these too

   yeah

Edit: Для тех, кто хочет модифицированную версию подпрограммы, которая теперь работает, вот она:

:catMyChunk
    ::Should call this function with 2 args, MYDELIM and outFile.txt
    ::where is to be catted to outFile.txt
    ::and text starts with <beginning of line>goto:MYDELIM
    ::and ends with <beginning of line>:MYDELIM
    set searchStart=goto:%~1
    set searchStop=:%~1
    set outFile=%~2
    set startLine=0
    set endLine=0
    for /f "delims=:" %%a in ('findstr -b -n !searchStart! %~dpnx0') do set "startLine=%%a"
    for /f "delims=:" %%a in ('findstr -b -n !searchStop!  %~dpnx0') do set "endLine=%%a"

    set /a linesLeftToRead=%endLine% - %startLine%
    del %outFile%
    if "%linesLeftToRead%" LEQ "0" (
        echo Error finding start and end delmieters for %searchStop% in catMyChunk routine
        exit /B 1
    )
    setlocal DisableDelayedExpansion
    for /f "usebackq skip=%startLine% delims=" %%a in (`"findstr /n ^^ %~dpnx0"`) do (
        set "oneLine=%%a"
        set /a linesLeftToRead-=1
        setlocal EnableDelayedExpansion
        set "oneLine=!oneLine:*:=!"
        if !linesLeftToRead! LEQ 0 exit /B
        echo(!oneLine!>>%outFile%
        endlocal
    )
    endlocal

goto: EOF

Ответы [ 2 ]

2 голосов
/ 01 ноября 2011

+ 1, интересное приложение!Я изменил ваш код для более простой и быстрой версии:

@echo off
call :catMyChunk myCustomText see.txt
exit /b

goto:myCustomText
This is my test file
Hope you like it.
<got these>
% and these %
! these too
yeah
:myCustomText

:catMyChunk
::Should call this function with 2 args, MYDELIM and outFile.txt
::where is to be catted to outFile.txt
::and text starts with <beginning of line>goto:MYDELIM
::and ends with <beginning of line>:MYDELIM
setlocal DisableDelayedExpansion
set searchStart=goto:%~1
set searchStop=:%~1
set outFile=%~2
if exist %outFile% del %outFile%
set copyFlag=No
echo No> copyFlag
for /f "delims=" %%a in (%~f0) do (
    set "oneLine=%%a"
    setlocal EnableDelayedExpansion
    if !copyFlag! == No (
        if !oneLine! == %searchStart% echo Yes> copyFlag
    ) else (
        if !oneLine! == %searchStop% (
            echo No> copyFlag
        ) else (
            echo/!oneLine!>> %outFile%
        )
    )
    endlocal
    set /p copyFlag=< copyFlag
)
endlocal
goto :eof

Я также создал другую версию, которая больше похожа на версию Linux, то есть строки для копирования помещаются непосредственно после вызова подпрограммы, ивыполнение продолжается после последней скопированной строки.Конечно, чтобы сделать это возможным, подпрограмма не вызывается через call, а вводится с goto, и когда подпрограмма заканчивается, она выполняет goto %MYDELIM% вместо «return» (exit /b или goto :eof).Кроме того, поскольку goto не может иметь параметры, «параметры» определяются в переменных перед вызовом.

@echo off
set searchStop=EndOfMyText
set outFile=see.txt
goto :catMyChunk EndOfMyText
This is my test file
Hope you like it.
<got these>
% and these %
! these too
yeah
:EndOfMyText
exit /b


:catMyChunk
::Before JUMP to this "function" define 2 vars: searchStop and outFile
::where is to be catted to %outFile%
::and text starts with goto :catMyChunk %searchStop%
::and ends with :%searchStop%
setlocal DisableDelayedExpansion
set searchStart=goto :catMyChunk %searchStop%
if exist %outFile% del %outFile%
set copyFlag=No
echo No> copyFlag
for /f "delims=" %%a in (%~f0) do (
    set "oneLine=%%a"
    setlocal EnableDelayedExpansion
    if !copyFlag! == No (
        if /I !oneLine! == !searchStart! echo Yes> copyFlag
    ) else (
        if !oneLine! == :%searchStop% (
            echo No> copyFlag
        ) else (
            echo/!oneLine!>> %outFile%
        )
    )
    endlocal
    set /p copyFlag=< copyFlag
)
endlocal
goto %searchStop%

РЕДАКТИРОВАТЬ

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

:catMyChunk
::Should call this function with 2 args, MYDELIM and outFile.txt
::where is to be catted to outFile.txt
::and text starts with <beginning of line>goto:MYDELIM
::and ends with <beginning of line>:MYDELIM
setlocal EnableDelayedExpansion
set searchStart=goto:%~1
set searchStop=:%~1
set outFile=%~2
if exist %outFile% del %outFile%
findstr /n ^^ "%~f0" > pipeline.txt
call :seekMyChunk < pipeline.txt
del pipeline.txt
exit /B

:seekMyChunk
set oneLine=:EOF
set /P oneLine=
if !oneLine! == :EOF goto startNotFound
set oneLine=!oneLine:*:=!
if not !oneLine! == %searchStart% goto seekMyChunk
:catNextLine
set oneLine=:EOF
set /P oneLine=
if !oneLine! == :EOF goto stopNotFound
set oneLine=!oneLine:*:=!
if !oneLine! == %searchStop% goto :eof
echo/!oneLine!>> %outFile%
goto catNextLine
:startNotFound
echo Error finding start delimiter for %searchStart% in catMyChunk 
goto :eof
:stopNotFound
echo Error finding stop delimiter for %searchStop% in catMyChunk 
goto :eof
2 голосов
/ 31 октября 2011

В вашем коде отсутствует один endlocal в вашем FOR-цикле.
Вы создаете для каждого цикла новый локальный контекст через setlocal EnableDelayedExpansion, это взорвется еще несколькими строками в вашем текстовом файле.

И для сохранения восклицательных знаков (а также каретки) вам нужна техника переключения Пакетные файлы DOS: Как прочитать файл?

setlocal DisableDelayedExpansion
for /f "usebackq skip=%startLine% delims=" %%a in (`"findstr /n ^^ %~dpnx0"`) do (
    set "oneLine=%%a"
    setlocal EnableDelayedExpansion
    set "oneLine=!oneLine:*:=!"
    set /a linesLeftToRead-=1
    if !linesLeftToRead! LEQ 0 exit /B
    echo(!oneLine!>>%outFile%
    **endlocal**
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...