Как использовать функцию Windows CMD pipe (|) с параметром CALL: Label?
У меня есть неприятная проблема, когда я хочу использовать функцию pipe (|) с опцией Shell CMF оболочки CALL: Label. У меня есть очень маленький пример (ниже): call-test.cmd и выходной файл.
Нуль проблемы был/должен передавать вывод CMD script в другую программу, например утилиту tee, или find. Например:
@call :Label-02 param | tee call-test.log
Запустится текущий командный файл на ярлыке Label-02 и выведет его на tee. К сожалению, использование символа трубы (|) в строке с опцией "звонок: метка" дает ошибку:
Invalid attempt to call batch label outside of batch script.
В то время как " вызов example.cmd | tee example.log" работает нормально.
Другое перенаправление IO работает нормально. Это единственный случай, когда используется " call: label pipe (|)", который терпит неудачу. Для меня это просто похоже на ошибку Windows.
Есть ли у кого-нибудь обходное решение и/или знать объяснение?
Спасибо, Будет ли
-
вывод вызова
c:\> call-test
[start]
label 03 :: p1
Invalid attempt to call batch label outside of batch script.
Invalid attempt to call batch label outside of batch script.
[done]
Press any key to continue . . .
-
колл-тест
@echo off
@rem call-test.cmd
@rem _________________________________________________
@rem Test :label call option for .cmd files.
@rem
@echo ^ [start]
@call :Label-03 p1
@call :Label-02 second | find " "
@call :Label-02 second | tee call-test.log
@goto Done
@rem _________________________________________________
:Label-01
@echo ^ label 01 :: %1
@goto Exit
@rem _________________________________________________
:Label-02
@echo ^ label 02 :: %1
@goto Exit
@rem _________________________________________________
:Label-03
@echo ^ label 03 :: %1
@goto Exit
@rem _________________________________________________
:Done
@echo ^ [done]
@pause
@rem _________________________________________________
:Exit
@exit /b
Ответы
Ответ 1
Причина в том, что труба запускается с обеих сторон в контексте cmd (оба выполняются параллельно в одном CMD-окне), и каждая сторона интерпретируется как аргумент реальной командной строки, а на метках линии cmd не допускается.
Но вы можете вызвать свою функцию, если вы перезапустите пакет.
if not "%1"=="" goto %1
@call "%~0" :Label-02 param | tee call-test.log
EDIT: полный образец
@echo off
if not "%~1"=="START" goto :normalStart
shift
shift
call %0 %1 %2 %3 %4 %5 %6 %7 %8
exit /b
:normalStart
rem call-test.cmd
rem _________________________________________________
rem Test :label call option for .cmd files.
rem
echo ^ [start]
rem call :Label-03 p1
rem call :Label-02 second | find " "
call "%~dpf0" "START" :Label-02 second | tee call-test.log
goto Done
rem _________________________________________________
:Label-01
echo ^ label 01 :: %1
goto Exit
rem _________________________________________________
:Label-02
echo ^ label 02 :: %1
goto Exit
rem _________________________________________________
:Label-03
echo ^ label 03 :: %1
goto Exit
rem _________________________________________________
:Done
echo ^ [done]
pause
rem _________________________________________________
:Exit
exit /b
Ответ 2
Очевидным обходным решением является перенаправление вывода вызова на временный файл, использование его в качестве входа для find/tee, а затем удаление файла:
@call :Label-02 second > tmp
tee call-test.log < tmp
delete tmp
Ответ 3
Я понимаю, что это немного поздно, но может быть полезно для других. это не совсем взломать, более обходным путем. Или довольно "хороший взлом", если нужно.
Я использую следующее решение для аналогичной проблемы:
@echo off
SET CURRENT_SCRIPT_IS=%~dpnx0
IF NOT "%RUN_TO_LABEL%" == "" (
call :%RUN_TO_LABEL% %1 %2 %3 %4 %5 %6 %7 %8 %9
goto:eof
)
goto over_debug_stuff
:debugstr
echo %~1
echo %~1>>%2
goto:eof
:debuglbl
SET RUN_TO_LABEL=%1
for /f "tokens=*" %%L in ('%CURRENT_SCRIPT_IS% %3 %4 %5 %6 %7 %8 %9') do (
echo %%L
echo %%L>>%2
)
SET RUN_TO_LABEL=
goto:eof
:over_debug_stuff
call :debugstr "this is a string" "test_str.txt"
call :debuglbl tst "test_lbl.txt"
goto:eof
:tst
echo label line 1
echo label line 2
echo label line 3
goto:eof
Хорошая вещь в том, что я могу скопировать-вставить "заголовок" в любой пакет script Мне нужно запустить его. Я не потрудился сделать его рекурсивным, поскольку мне это не нужно, поэтому убедитесь, что вы проверили этот сценарий, прежде чем вводить его.
Очевидно, что у меня есть функции обертки для этих отладочных * вызовов, так что я не переношу файл журнала с каждым вызовом. Кроме того, в моих отладочных журнальных вызовах я также проверяю флаг отладки, поэтому сама оболочка имеет в себе более логичную логику, которая в основном зависит от используемого script.
Ответ 4
Я думаю, вы можете использовать "|" то труба обрабатывается как обычный символ.
Ответ 5
Это более лаконичная версия ответа на фразу.
Он использует ту же технологию goto, но вместо того, чтобы передавать уникальный параметр "START" при повторном входе, он проверяет, является ли первый символ первого параметра ":", используя извлечение подстроки и только вызовы goto, если это метка. Это упрощает вызов, однако вы не можете использовать извлечение подстроки с переменными% 1 или пустые/несуществующие переменные, поэтому она должна использовать временную переменную, которая всегда содержит значение. Ему все равно нужен temp var, чтобы запомнить метку, поскольку SHIFT /1
удалит первый параметр: LABEL, но он должен использовать SHIFT один раз и не требует дополнительного параметра на сайте вызова.
[ update: должен сделать SHIFT /1
, чтобы избежать изменения% 0 в случае, если он используется script]
set "LABEL=%~1_"
if "%LABEL:~0,1%"==":" SHIFT /1 & goto %LABEL:~0,-1%
Итак, следующий script показывает, как вы можете использовать параметры, переданные исходному script, а также повторно вводить для обработки меток:
@echo off
set "LABEL=%~1_"
if "%LABEL:~0,1%"==":" SHIFT /1 & goto %LABEL:~0,-1%
call "%~f0" :LABEL_TEST param1 p2 | findstr foo
echo param 1 is %1
exit /b
:LABEL_TEST
echo (foo) called label with PARAMS: %1 %2 %3
echo (bar) called label with PARAMS: %1 %2 %3
exit /b
выведет:
C:\>call-test-with-params TEST
(foo) called label with PARAMS: param1 p2
param 1 is TEST
строка echo (bar)
лишена трубой для findstr
решение вопроса:
Этот script:
@echo off
set "LABEL=%~1_"
if "%LABEL:~0,1%"==":" SHIFT /1 & goto %LABEL:~0,-1%
@rem call-test.cmd
@rem _________________________________________________
@rem Test :label call option for .cmd files.
@rem
@echo ^ [start]
@call "%~f0" :Label-03 p1
@call "%~f0" :Label-02 second | find " "
@call "%~f0" :Label-02 second | tee call-test.log
@goto Done
@rem _________________________________________________
:Label-01
@echo ^ label 01 :: %1
@goto Exit
@rem _________________________________________________
:Label-02
@echo ^ label 02 :: %1
@goto Exit
@rem _________________________________________________
:Label-03
@echo ^ label 03 :: %1
@goto Exit
@rem _________________________________________________
:Done
@echo ^ [done]
@pause
@rem _________________________________________________
:Exit
@exit /b
будет эхо:
C:\>call-test
[start]
label 03 :: p1
label 02 :: second
label 02 :: second
[done]
Press any key to continue . . .
И call-test.log
имеет правильный контент:
C:\>more call-test.log
label 02 :: second
Ответ 6
поставьте ^
перед командой pipe... например.
@call :Label-02 second ^| find " "