J'ai un problème frustrant lorsque je veux utiliser la fonctionnalité pipe (|) avec l'option CALL: Label du shell CMD de la fenêtre. J'ai un très petit exemple (ci-dessous): call-test .cmd et exemple de sortie.
Le nœud du problème était/consiste à diriger la sortie d'un script CMD vers un autre programme, par exemple l'utilitaire tee ou la commande find. Par exemple:
@call :Label-02 param | tee call-test.log
Ce qui lancerait le fichier de commande actuel à l’étiquette Label-02 et dirigerait la sortie vers tee. Malheureusement, l'utilisation du caractère de canal (|) sur la ligne avec l'option "call: label" donne une erreur:
Invalid attempt to call batch label outside of batch script.
Alors que "call example.cmd | tee example.log" fonctionne très bien.
L'autre redirection IO > fonctionne correctement. C'est le seul cas où "call: label pipe" (|) "est utilisé et qui échoue. Pour moi, cela ressemble à un bug de Windows.
Est-ce que quelqu'un a une solution de contournement et/ou est au courant d'une explication?
Merci, Volonté
sortie de test d'appel
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 . . .
call-test
@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
La raison en est qu'un tuyau commence les deux côtés dans un contexte cmd (les deux sont parallèles dans une boîte à cmd), et que chaque côté est interprété comme un véritable argument de ligne de commande et que les étiquettes de ligne de commande ne sont pas autorisées.
Mais vous pouvez appeler votre fonction si vous redémarrez votre lot.
if not "%1"=="" goto %1
@call "%~0" :Label-02 param | tee call-test.log
EDIT: L'échantillon complet
@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
La solution évidente consiste à rediriger la sortie de l'appel vers un fichier temporaire, à l'utiliser comme entrée pour find/tee, puis à supprimer le fichier:
@call :Label-02 second > tmp
tee call-test.log < tmp
delete tmp
Je réalise que cela arrive un peu tard, mais pourrait être utile pour les autres. ce n'est pas tout à fait un bidouillage, plus une solution de contournement. Ou joli "Nice hack" si vous devez .. .. J'utilise la solution suivante à un problème similaire:
@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
La bonne chose à ce sujet est que je peux copier-coller "l'en-tête" dans n'importe quel script batch dont j'ai besoin pour l'exécuter. Je ne me suis pas soucié de le rendre sûr, car je n'en avais pas besoin, alors Testez ce scénario avant de le mettre dans . De toute évidence, j'ai des fonctions d'emballage sur ces appels de débogage *, de sorte que je ne porte pas le fichier journal avec chaque appel. De plus, dans mes appels au journal de débogage, je teste également l'indicateur de débogage, de sorte que le wrapper lui-même a plus de logique, ce qui dépend principalement du script utilisé dans.
Ceci est une version plus succincte de la réponse jebs.
Il utilise la même technique goto, mais au lieu de passer un paramètre "START" unique lors de la nouvelle saisie, il teste si le premier caractère du premier paramètre est ":" à l'aide d'une extraction de sous-chaîne et appelle uniquement goto si c'est le cas. une marque. Cela simplifie l'appel, toutefois, vous ne pouvez pas utiliser l'extraction de sous-chaîne avec des variables% 1 ou des variables vides/inexistantes. Vous devez donc utiliser une variable temporaire qui contient toujours une valeur. Quoi qu'il en soit, il a besoin de la variable temp pour mémoriser l'étiquette car SHIFT /1
supprime le premier paramètre: LABEL, mais il ne doit utiliser qu'une fois SHIFT et ne nécessite pas de paramètre supplémentaire sur le site de l'appel.
[update: doit faire shift /1
pour éviter de changer% 0 au cas où il serait utilisé par le script]
set "LABEL=%~1_"
if "%LABEL:~0,1%"==":" SHIFT /1 & goto %LABEL:~0,-1%
Ainsi, le script suivant montre comment utiliser les paramètres transmis au script d'origine, ainsi que pour le ressaisir afin de traiter les étiquettes:
@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
affichera:
C:\>call-test-with-params TEST
(foo) called label with PARAMS: param1 p2
param 1 is TEST
la ligne echo (bar)
étant arrachée par le tuyau pour findstr
Ce 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
va faire écho:
C:\>call-test
[start]
label 03 :: p1
label 02 :: second
label 02 :: second
[done]
Press any key to continue . . .
Et call-test.log
a le contenu correct:
C:\>more call-test.log
label 02 :: second
Je pense que vous pouvez utiliser "|" alors la pipe est traitée comme un caractère ordinaire.