2016-06-23 11 views
0

Ich verwende die Technik in der Antwort auf this question, um eine Batch-Datei eine andere Datei ausgeben zu lassen. Das Problem ist, dass wenn ich das "&" Symbol erreiche, bekomme ich Fehler. Hier ist meine Batch-Datei, gefolgt von dem Fehlerausgang:Führt "&" zu einer Unterbrechung des echo-Befehls, wie wird das behoben?

@echo off>zip.vbs 
@echo 'Get command-line arguments.>>zip.vbs 
@echo Set objArgs = WScript.Arguments>>zip.vbs 
@echo InputFolder = objArgs(0)>>zip.vbs 
@echo ZipFile = objArgs(1)>>zip.vbs 
@echo >>zip.vbs 
@echo 'Create empty ZIP file.>>zip.vbs 
@echo CreateObject("Scripting.FileSystemObject").CreateTextFile(ZipFile, True).Write "PK" & Chr(5) & Chr(6) & String(18, vbNullChar)>>zip.vbs 
@echo >>zip.vbs 
@echo Set objShell = CreateObject("Shell.Application")>>zip.vbs 
@echo >>zip.vbs 
@echo Set source = objShell.NameSpace(InputFolder).Items>>zip.vbs 
@echo >>zip.vbs 
@echo objShell.NameSpace(ZipFile).CopyHere(source)>>zip.vbs 
@echo >>zip.vbs 
@echo 'Required!>>zip.vbs 
@echo wScript.Sleep 2000>>zip.vbs 

, die diese erzeugt zip2.vbs Datei:

'Get command-line arguments. 
Set objArgs = WScript.Arguments 
InputFolder = objArgs(0) 
ZipFile = objArgs(1) 
ECHO is off. 
'Create empty ZIP file. 
ECHO is off. 
Set objShell = CreateObject("Shell.Application") 
ECHO is off. 
Set source = objShell.NameSpace(InputFolder).Items 
ECHO is off. 
objShell.NameSpace(ZipFile).CopyHere(source) 
ECHO is off. 
'Required! 
wScript.Sleep 2000 

Und diesen Fehlerausgang:

E:\scripts>zip2 
CreateObject("Scripting.FileSystemObject").CreateTextFile(ZipFile, True).Write " 
PK" 
'Chr' is not recognized as an internal or external command, 
operable program or batch file. 
'Chr' is not recognized as an internal or external command, 
operable program or batch file. 
'String' is not recognized as an internal or external command, 
operable program or batch file. 
+0

Das Ampersand hat eine besondere Bedeutung für 'cmd', nämlich den Befehl Verkettungsoperator, wie' echo abc & echo def'; um ein literales '' '' 'zu hallen, müssen Sie es wie'^& '; Dasselbe gilt für '<', '>', '|' und '^', sowie '(' und ')', wenn der Befehl 'echo' in einem geklammerten Codeblock liegt. Um eine leere Zeile auszugeben, benutzen Sie 'echo ('. Ich empfehle, die Umleitung an den Anfang der Zeile zu setzen, wie '>>" zip.vbs "echo Some text.' oder' >> "zip.vbs" echo (' um nachfolgende Leerzeichen in der Ausgabe oder seltsames Verhalten zu vermeiden, falls das letzte Zeichen vor '>' eine Zahl ist – aschipfl

+0

"^" vor jedem "&" zu addieren, hat perfekt funktioniert. Sieht so aus, als ob dein Kommentar eine Antwort sein sollte! Danke. –

+0

Es kommt bald ... – aschipfl

Antwort

1

Zunächst lassen Sie mich sorgen Sie für eine schnelle und schmutzige Korrektur Ihres Codes; Erklärungen folgen unten:

@echo off 
> "zip.vbs" echo('Get command-line arguments. 
>>"zip.vbs" echo(Set objArgs = WScript.Arguments 
>>"zip.vbs" echo(InputFolder = objArgs(0) 
>>"zip.vbs" echo(ZipFile = objArgs(1) 
>>"zip.vbs" echo(
>>"zip.vbs" echo('Create empty ZIP file. 
>>"zip.vbs" echo(CreateObject("Scripting.FileSystemObject").CreateTextFile(ZipFile, True).Write "PK" ^& Chr(5) ^& Chr(6) ^& String(18, vbNullChar) 
>>"zip.vbs" echo(
>>"zip.vbs" echo(Set objShell = CreateObject("Shell.Application") 
>>"zip.vbs" echo(
>>"zip.vbs" echo(Set source = objShell.NameSpace(InputFolder).Items 
>>"zip.vbs" echo(
>>"zip.vbs" echo(objShell.NameSpace(ZipFile).CopyHere(source) 
>>"zip.vbs" echo(
>>"zip.vbs" echo('Required! 
>>"zip.vbs" echo(wScript.Sleep 2000 

Der Ampersand hat eine besondere Bedeutung zu cmd, ist es der Befehl Verkettungsoperator; Geben Sie beispielsweise echo abc & echo def ein, um zwei echo Befehle in einer einzigen Zeile zu setzen.

Um ein Literal & auszugeben, müssen Sie es durch den Caret wie ^& entkommen. Gleiches gilt für <, > und | und die ^ selbst. Falls der echo Befehl innerhalb eines geklammerten Codeblocks liegt, müssen Sie auch ( und ) fliehen, ansonsten ist es optional (daher empfehle ich, sie trotzdem zu entfernen).

Um eine leere Zeile auszugeben, verwenden Sie echo(, da echo den Ein/Aus-Status von Befehl-Echo zurückgibt, wie ECHO is on/off.. Es gibt weit verbreitete Methoden wie echo. und echo/ um das gleiche zu erreichen, aber es gibt Situationen, in denen sich diese merkwürdig verhalten. echo( ist der einzige sichere Weg (obwohl seine Syntax ziemlich merkwürdig aussieht, muss ich zugeben). Übrigens, echo( kann auch zum Echo nicht leeren Text verwendet werden.

Wenn Sie Befehl-Echoing global von einem nicht umgeleiteten @echo off deaktivieren, müssen Sie nicht jeder weiteren Befehlszeile @ voranstellen.

Ich empfehle den Umleitungsteil (>>zip.vbs) an den Anfang der Zeile in Ordnung zu bringen seltsame Verhalten zu vermeiden, falls die wiederholte Zeichenfolge mit einer einzelnen Ziffer endet, da dies als die Stromkennung für die Umleitung behandelt werden kann (0ist STDIN, 1 ist STDOUT, 2 ist STDERR und 3 zu 9 sind undefiniert; < ist die gleiche wie 0< und >/>> ist die gleiche wie 1>/1>>). Beispiel: echo X=2>"zip.vbs" würde X= auf der Konsole als angezeigt. STDOUT wird nicht umgeleitet, und schreiben Sie nichts in als STDERR ist hier leer. Sie könnten dies vermeiden, indem Sie eine SPACE vor die > einfügen, aber es würde auch Echo sein. Ein besserer Weg ist es, die gesamte echo Befehlszeile zwischen () zu setzen, so dass die Zahl von > getrennt wird. Aber die beste Lösung sollte das sein: >"zip.vbs" echo X=2.


Sie können auch mehrere Umleitungen vermeiden und so viele Dateizugriffe, wenn Sie innerhalb eines parenthesised Block alle echos setzen sollten, die nur einmal umgeleitet wird (aber, wie oben beschrieben, nicht zu vergessen die Klammern, jetzt hier zu entkommen):

@echo off 
> "zip.vbs" (
    echo('Get command-line arguments. 
    echo(Set objArgs = WScript.Arguments 
    echo(InputFolder = objArgs^(0^) 
    echo(ZipFile = objArgs^(1^) 
    echo(
    echo('Create empty ZIP file. 
    echo(CreateObject^("Scripting.FileSystemObject"^).CreateTextFile^(ZipFile, True^).Write "PK" ^& Chr^(5^) ^& Chr^(6^) ^& String^(18, vbNullChar^) 
    echo(
    echo(Set objShell = CreateObject^("Shell.Application"^) 
    echo(
    echo(Set source = objShell.NameSpace^(InputFolder^).Items 
    echo(
    echo(objShell.NameSpace^(ZipFile^).CopyHere^(source^) 
    echo(
    echo('Required! 
    echo(wScript.Sleep 2000 
) 

ist hier ein völlig anderer Ansatz, in dem nicht mehr entkommen getan werden muss. Das VBScript-Skript ist direkt nach dem ausführbaren Batch-Code in die Batch-Datei eingebettet. Damit dies funktioniert, müssen Sie exit /B vor dem VBScript-Teil platzieren. Der VBScript-Teil wird dadurch identifiziert, dass er sich zwischen einem Paar von Zeilen befindet, die nur aus bestehen (dies bedeutet, dass die gesamte Batch-Datei einschließlich des VBScript-Teils keine solche Zeile enthalten darf; alternativ kann jeder VBScript-Zeile ein bestimmter Identifizierer vorangestellt werden) Präfix, das später entfernt wird, aber das Prinzip ist das gleiche). Mit dieser Methode werden die VBScript-Zeilen buchstäblich ausgegeben, es ist absolut kein Entkommen erforderlich. So hier gehen wir:

@echo off 
setlocal EnableExtensions DisableDelayedExpansion 

set "FLAG=" 
> "zip.vbs" (
    for /F "delims=" %%L in ('findstr /N /R "^" "%~f0"') do (
     set "LINE=%%L" 
     setlocal EnableDelayedExpansion 
     set "LINE=!LINE:*:=!" 
     if not "!LINE:#=!"=="" (
      if defined FLAG (echo(!LINE!) 
     ) else (
      endlocal 
      if defined FLAG (set "FLAG=") else (set "FLAG=#") 
      setlocal EnableDelayedExpansion 
     ) 
     endlocal 
    ) 
) 

endlocal 
exit /B 


################################################################################ 
'Get command-line arguments. 
Set objArgs = WScript.Arguments 
InputFolder = objArgs(0) 
ZipFile = objArgs(1) 

'Create empty ZIP file. 
CreateObject("Scripting.FileSystemObject").CreateTextFile(ZipFile, True).Write "PK" & Chr(5) & Chr(6) & String(18, vbNullChar) 

Set objShell = CreateObject("Shell.Application") 

Set source = objShell.NameSpace(InputFolder).Items 

objShell.NameSpace(ZipFile).CopyHere(source) 

'Required! 
wScript.Sleep 2000 
################################################################################ 

Die gesamte Batch-Datei durch eine for /F Schleife gelesen wird. Da dies leere Zeilen ignoriert, wird findstr verwendet, um jeder Zeile mit ihrer Zeilennummer und einem Doppelpunkt zu vorangehen, der nicht leer zu for /F erscheint. Dieses Präfix wird später in der Schleife entfernt. Die Variable FLAG wird am Anfang gelöscht und wird umgeschaltet, sobald eine Zeile gefunden wurde, die nur aus Zeichen besteht. Wenn FLAG nicht leer ist, wird die aktuelle Zeile ausgegeben, andernfalls nicht. Die verzögerte Erweiterung wird umgeschaltet, um keine Ausrufezeichen im Text zu verlieren.