Как использовать функцию 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 " "