web-dev-qa-db-fra.com

Comment supprimer les guillemets d'une chaîne ECHOed dans un fichier batch Windows?

J'ai un fichier batch Windows que je crée, mais je dois ECHO une grande chaîne complexe, donc je dois mettre des guillemets doubles à chaque extrémité. Le problème est que les guillemets sont également enregistrés dans le fichier dans lequel je l'écris. Comment pouvez-vous ECHO une chaîne comme ça et supprimer les guillemets?

MISE À JOUR:

J'ai passé les deux derniers jours à travailler là-dessus et j'ai finalement pu claquer quelque chose ensemble. La réponse de Richard a fonctionné pour supprimer les guillemets, mais même lorsque j'ai mis ECHO dans le sous-programme et sorti directement la chaîne, Windows a toujours raccroché aux caractères de la chaîne. J'accepte la réponse de Richard car elle répond à la question posée.

J'ai fini par utiliser la solution sed de Greg, mais j'ai dû la modifier en raison de sed/windows bugs/features (cela n'a pas aidé qu'elle ne soit accompagnée d'aucune documentation). Il y a quelques mises en garde à utiliser sed dans Windows: vous devez utiliser des guillemets doubles au lieu de guillemets simples, vous ne pouvez pas échapper directement les guillemets doubles dans la chaîne, vous devez mettre des guillemets finaux, échapper en utilisant le ^ (donc ^ " ), puis citez la section suivante. De plus, quelqu'un a fait remarquer que si vous dirigez l'entrée vers sed, il y a un bogue avec un tuyau dans la chaîne (je n'ai pas pu le vérifier car dans ma solution finale, je viens de trouver un moyen de ne pas avoir toutes les guillemets au milieu de la chaîne, et juste de supprimer toutes les guillemets, je n'ai jamais pu faire supprimer la guillemet final par elle-même.) Merci pour toute l'aide.

38
Lance Roberts

La commande call a cette fonctionnalité intégrée. Pour citer l'aide pour l'appel:

 Substitution of batch parameters (%n) has been enhanced.  You can
 now use the following optional syntax:

 %~1         - expands %1 removing any surrounding quotes (")

Voici un exemple primitif:

@echo off
setlocal
set mystring="this is some quoted text"
echo mystring=%mystring%
call :dequote %mystring%
echo ret=%ret%
endlocal
goto :eof

:dequote
setlocal
rem The tilde in the next line is the really important bit.
set thestring=%~1
endlocal&set ret=%thestring%
goto :eof

Production:

C:\>dequote
mystring="this is some quoted text"
ret=this is some quoted text

Je dois créditer la technique de "tunnelage des variables d'environnement" (endlocal & set ret =% thestring%) à Tim Hill, "Windows NT Shell Scripting" . C'est le seul livre que j'aie jamais trouvé qui traite des fichiers batch avec une quelconque profondeur.

54
Richard A

Vous pouvez utiliser le %var:x=y% construction qui remplace tout x par y.

Voir cet exemple ce qu'il peut faire:

set I="Text in quotes"
rem next line replaces " with blanks
set J=%I:"=%
echo original %I%
rem next line replaces the string 'in' with the string 'without' 
echo stripped %J:in=without%
10
Big Joe

L'approche suivante peut être utilisée pour imprimer une chaîne sans guillemets:

echo|set /p="<h1>Hello</h1>"
7
Daniel Budzyński

Pour supprimer tous les guillemets d'une variable définie, vous avez besoin d'une extension de variable retardée pour développer en toute sécurité la variable et la traiter. Expansion à l'aide de signes de pourcentage (c'est-à-dire %VAR% et %1) sont intrinsèquement dangereux (ils sont vulnérables à l'injection de commandes; lire ceci pour plus de détails ).

SETLOCAL EnableDelayedExpansion
SET VAR=A ^"quoted^" text.
REM This strips all quotes from VAR:
ECHO !VAR:^"=!
REM Really that's it.

Pour supprimer les guillemets d'un fichier texte ou d'une sortie de commande, les choses vont se compliquer car avec Delayed Expansion, une chaîne comme !VAR! dans le document texte sera développé (dans le %%i expansion dans FOR /F) alors qu'il ne devrait pas. (Il s'agit d'une autre vulnérabilité - la divulgation d'informations - qui n'est pas documentée ailleurs.)

Pour analyser le document en toute sécurité, un basculement entre l'environnement à extension différée activée et désactivé est nécessaire.

REM Suppose we fetch the text from text.txt

SETLOCAL DisableDelayedExpansion
REM The FOR options here employs a trick to disable both "delims"
REM characters (i.e. field separators) and "eol" character (i.e. comment
REM character).
FOR /F delims^=^ eol^= %%L IN (text.txt) DO (

    REM This expansion is safe because cmd.exe expands %%L after quotes
    REM parsing as long as DelayedExpansion is Disabled. Even when %%L
    REM can contain quotes, carets and exclamation marks.
    SET "line=%%L"

    CALL :strip_quotes
    REM Print out the result. (We can't use !line! here without delayed
    REM expansion, so do so in a subroutine.)
    CALL :print_line
)
ENDLOCAL
GOTO :EOF

REM Reads !line! variable and strips quotes from it.
:strip_quotes
    SETLOCAL EnableDelayedExpansion
    SET line=!line:^"=!

    REM Make the variable out of SETLOCAL
    REM I'm expecting you know how this works:
    REM (You may use ampersand instead:
    REM `ENDLOCAL & SET "line=%line%"`
    REM I just present another way that works.)
    (
    ENDLOCAL
    SET "line=%line%"
    )
GOTO :EOF

:print_line
    SETLOCAL EnableDelayedExpansion
    ECHO !line!
    ENDLOCAL
GOTO :EOF

Le delims^=^ eol^= dans le code ci-dessus doit probablement être expliqué: cela désactive efficacement les caractères "délimiteurs" (c'est-à-dire les séparateurs de champs) et les caractères "eol" (c'est-à-dire les caractères de commentaire). Sans cela, les "délimitations" seront par défaut tabulées et espacées et "eol" par défaut sera un point-virgule.

  • Le eol= le jeton lit toujours le caractère suivant après le signe égal. Pour le désactiver, ce jeton doit se trouver à la fin de la chaîne d'options afin qu'aucun caractère ne puisse être utilisé pour "eol", ce qui le désactive effectivement. Si la chaîne d'options est entre guillemets, elle peut utiliser le guillemet (") comme" eol ", nous ne devons donc pas citer la chaîne d'options.
  • Le delims= option, quand ce n'est pas la dernière option dans la chaîne d'options, sera terminée par un espace. (Pour inclure de l'espace dans les "délimitations", il doit s'agir de la dernière option de FOR /F options.) Donc delims= suivi d'un espace, puis une autre option désactive les "délimitations".
3
Explorer09

Je sais que ce n'est pas vraiment pour l'auteur, mais si vous avez besoin d'envoyer du texte dans le fichier sans guillemets - la solution ci-dessous fonctionne pour moi. Vous n'avez pas besoin d'utiliser des guillemets dans la commande echo, entourez simplement la commande complète de crochets.

(
    echo first very long line
    echo second very long line with %lots% %of% %values%
) >"%filename%"
2
cyber_by

Cela transformera "C:\Program Files\somefile.txt" en C:\Program Files\somefile.txt tout en conservant des cas tels que Height=5'6" et Symbols="!@#

:DeQuote

SET _DeQuoteVar=%1
CALL SET _DeQuoteString=%%!_DeQuoteVar!%%
IF [!_DeQuoteString:~0^,1!]==[^"] (
IF [!_DeQuoteString:~-1!]==[^"] (
SET _DeQuoteString=!_DeQuoteString:~1,-1!
) ELSE (GOTO :EOF)
) ELSE (GOTO :EOF)
SET !_DeQuoteVar!=!_DeQuoteString!
SET _DeQuoteVar=
SET _DeQuoteString=
GOTO :EOF

Exemple

SetLocal EnableDelayedExpansion
set _MyVariable = "C:\Program Files\ss64\"
CALL :dequote _MyVariable
echo %_MyVariable%
2
JRL

La réponse ci-dessus (commençant par: DeQuote) suppose que l'expansion retardée des variables d'environnement est activée. De cmd /?:

L'expansion retardée des variables d'environnement n'est PAS activée par défaut. Vous pouvez activer ou désactiver l'extension de variable d'environnement retardée pour un appel particulier de CMD.EXE avec le commutateur/V: ON ou/V: OFF. Vous pouvez activer ou désactiver l'achèvement de toutes les invocations de CMD.EXE sur une session d'ouverture de session machine et/ou utilisateur en définissant l'une des valeurs REG_DWORD suivantes ou les deux dans le Registre à l'aide de REGEDT32.EXE:

HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\DelayedExpansion

    and/or

HKEY_CURRENT_USER\Software\Microsoft\Command Processor\DelayedExpansion

à 0x1 ou 0x0. Le paramètre spécifique à l'utilisateur a priorité sur le paramètre de la machine. Les commutateurs de ligne de commande ont priorité sur les paramètres du Registre.

Si l'expansion retardée des variables d'environnement est activée, le caractère d'exclamation peut être utilisé pour remplacer la valeur d'une variable d'environnement au moment de l'exécution.

2
james

Le fichier de commandes suivant démarre une série de programmes avec un délai après chacun.

Le problème est de passer une ligne de commande avec des paramètres pour chaque programme. Cela nécessite des guillemets autour de l'argument du programme, qui sont supprimés lors de l'appel. Cela illustre quelques techniques de traitement de fichiers par lots.

Recherchez dans le sous-programme local: mystart comment un argument entre guillemets est passé et les guillemets sont supprimés.

@echo off

rem http://www.Microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/if.mspx?mfr=true

rem Start programs with delay

rem  Wait n seconds
rem  n number retries to communicate with the IP address
rem  1000 milliseconds between the retries
rem  127.0.0.1 is the LocalHost
rem  start /b (silent)  /min (minimized) /belownormal (lower priority)
rem  /normal provides a no-op switch to hold the place of argument 1

rem  start  /normal "Opinions"  %SystemRoot%\Explorer.exe /e,d:\agar\jobs\opinion
rem  ping 127.0.0.1 -n 8 -w 1000 > nul

rem   Remove quotes in Batch
rem     http://ss64.com/nt/syntax-dequote.html
rem   String manipulation in Batch
rem     http://www.dostips.com/DtTipsStringManipulation.php
rem   ^ line continuation
rem   
rem   set p="One Two"      p has the exact value  "One Two" including the quotes           
rem   set p=%p:~1,-1%      Removes the first and last characters
rem   set p=%p:"=%         Removes all double-quotes
rem   set p=%p:cat=mouse%  Replaces cat with mouse

rem  ping 127.0.0.1 -n 12 -w 1000 > nul
rem        1       2            3                                                         4

@echo on
call :mystart /b/min  "Opinions"   "%SystemRoot%\Explorer.exe  /e,d:\agar\jobs\opinion"   8  
@echo on
call :mystart /b/min  "Notepad++"  D:\Prog_D\Notepad++\notepad++.exe  14
@echo on
call :mystart /normal "Firefox"    D:\Prog_D\Firefox\firefox.exe      20
@rem call :mystart /b/min "ProcessExplorer"  D:\Prog_D\AntiVirus\SysInternals\procexp.exe  8
@echo on
call :mystart /b/min/belownormal "Outlook" D:\Prog_D\MSOffice\OFFICE11\Outlook.exe  2
@echo off
goto:eof

:mystart
@echo off
 rem  %3 is "program-path  arguments" with the quotes. We remove the quotes
 rem  %4 is seconds to wait after starting that program
 set p=%3
 set p=%p:"=%
 start  %1  %2  %p% 
 ping 127.0.0.1 -n %4 -w 1000 > nul
 goto:eof
2
Andrew_M_Garland

L'utilisation de la commande FOR pour supprimer les guillemets environnants est le moyen le plus efficace que j'ai trouvé pour ce faire. Sous sa forme compacte (exemple 2), il s'agit d'une doublure.

Exemple 1: La solution à 5 lignes (commentée).

REM Set your string
SET STR=" <output file>    (Optional) If specified this is the name of your edited file"

REM Echo your string into the FOR loop
FOR /F "usebackq tokens=*" %%A IN (`ECHO %STR%`) DO (
    REM Use the "~" syntax modifier to strip the surrounding quotation marks
    ECHO %%~A
)

Exemple 2: l'exemple du monde réel à 1 ligne.

SET STR=" <output file>    (Optional) If specified this is the name of your edited file"

FOR /F "usebackq tokens=*" %%A IN (`ECHO %STR%`) DO @ECHO %%~A

Je trouve intéressant que l'écho interne ignore les caractères de redirection '<' et '>'.
Si vous exécutez ECHO asdfsd>asdfasd vous écrirez le fichier au lieu de la sortie standard.

J'espère que cela t'aides :)

Modifier:

J'y ai pensé et j'ai réalisé qu'il y avait une manière encore plus facile (et moins hacky) d'accomplir la même chose. Utilisez la substitution/expansion de variable améliorée (voir HELP SET) comme ça:

SET STR=" <output file>    (Optional) If specified this is the name of your edited file"

ECHO %STR:~1,-1%

Cela imprimera tout sauf les premier et dernier caractères (vos guillemets). Je recommanderais d'utiliser SETLOCAL ENABLEDELAYEDEXPANSION aussi. Si vous avez besoin de savoir où se trouvent les guillemets dans la chaîne, vous pouvez utiliser FINDSTR pour obtenir les caractères #.

1
TwoByteHero

La réponse de Daniel Budzyński est brillante. Cela fonctionne même dans les situations où il y a des caractères spéciaux dans la sortie. Par exemple:

C:\> for /f "usebackq tokens=2 delims=:" %i in (`%comspec%\..\ping -n 1 -w 200 10.200.1.1 ^| \
     findstr /c:"TTL="`) do echo|set /p="%i"

bytes=32 time<1ms TTL=255

Si vous essayez d'essayer un écho simple sans les guillemets, vous obtenez une erreur, en raison du "<" dans la variable:

C:\> set "output=bytes=32 time<1ms TTL=255"
C:\> echo %output%
The system cannot find the file specified.

C:\> echo|set /p="%output%"
bytes=32 time<1ms TTL=255
1
YDY

Méthode de la force brute:

echo "foo <3 bar" | sed -e 's/\(^"\|"$\)//g'

Cela nécessite bien sûr de trouver une version Win32 appropriée de sed.

0
Greg Hewgill

http://unxutils.sourceforge.net/ est un port natif win32 d'un tas d'utilitaires GNU comprenant sed, gawk, grep et wget. (désolé que je n'ont pas assez de représentants pour poster ceci en tant que commentaire!)

0
fearoffours