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.
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.
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%
L'approche suivante peut être utilisée pour imprimer une chaîne sans guillemets:
echo|set /p="<h1>Hello</h1>"
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.
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.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".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%"
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%
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.
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
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 #.
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
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
.
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!)