goodbytes
Goto Top

Problem For-Schleife in Batch

Hallo,
ich bin bald am verzweifeln. Mit einer Batch bearbeite ich alle jpg`s in einem Verzeichnis. Es soll jede Datei angefasst werden, mittels ZBarimg der Barcode darin gelesen werden und die Datei anschließend umbenannt werden. Es hatte auch schon funktioniert. Auf einen Schlag geht es nicht mehr.

Folgende Zeile sollte den Barcode aus jeder Datei auslesen und in eine Variable schreiben:

For /F "tokens=2 delims=':'" %%i in ('zbarimg "%1"') do Set "NEUERNAME=%%i"  

Trennzeichen soll der Doppelpunkt sein (der ausgelesene Code sieht so aus: CODE-128:M2013-007826).

Wenn ich statt "%1" einen Dateinamen eingebe klappt es wunderbar.

Wo liegt da der Fehler?

Torsten

Content-ID: 207973

Url: https://administrator.de/contentid/207973

Ausgedruckt am: 25.11.2024 um 17:11 Uhr

colinardo
colinardo 13.06.2013 aktualisiert um 14:50:19 Uhr
Goto Top
hallo Torsten,
lass mal die einfachen Anführungszeichen um den Doppelpunkt bei delims=':' weg. Sollte dann so aussehen delims=:
Grüsse Uwe
Endoro
Endoro 13.06.2013 um 14:50:19 Uhr
Goto Top
Hallo Torsten,

versuch es mal so:
For /F "tokens=2 delims=:" %%i in ('zbarimg "%~1"') do Set "NEUERNAME=%%i"  

Gruss!
goodbytes
goodbytes 13.06.2013 um 16:41:00 Uhr
Goto Top
Hallo,
nein, der Fehler lag woanders. Ich hatte nicht erwähnt, dass die Batch über ein vbs-Script gestartet wird, welches immer einen Dateinamen als Parameter übergibt:

oShell.Run "C:\Windows\System32\cmd.exe /c " & "D:\Barcode.cmd " & GetFileName_From_FilePath(file), 0, vbTrue  

Der Fehler lag tatsächlich in diesem Script, die Batch war in Ordnung.

Trotzdem danke für eure Antworten !!! face-smile

Gruß
Torsten
bastla
bastla 13.06.2013 um 19:26:36 Uhr
Goto Top
Hallo TorstenB!
die Batch war in Ordnung.
... aber hinsichtlich der von colinardo angesprochenen Apostrophe definitiv suboptimal - ein Apostroph davon kann sinnvoll sein (falls er tatsächlich als Delimiter gelten soll), 2 brauchst Du aber sicher nicht, da die "delims"-Angabe ohnehin nicht als String, sondern als Folge einzelner Trennzeichen interpretiert wird.

Grüße
bastla
goodbytes
goodbytes 17.06.2013 um 11:27:55 Uhr
Goto Top
Hallo Bastla,
alles klar, vielen Dank für die Info.

Vielen Dank auch an Uwe und Endoro !!! face-smile

Gruß
Torsteb
goodbytes
goodbytes 19.01.2016 aktualisiert um 11:40:42 Uhr
Goto Top
Hallo,
der Beitrag ist mittlerweile schon etwas älter und es hatte auch bestens funktioniert.
Mittlerweile haben sich aber auch viele Änderungen ergeben und in der Batch soll eigentlich nur noch der reine Barcode ausgelesen und zurück an das vbs-Script übergeben werden.
Nun meine Frage. Ich kann natürlich einen Befehl direkt in der vbs an die cmd übergeben:
Dim objWshShell: Set objWshShell = WScript.CreateObject("WScript.Shell")  
objWshShell.Run("cmd.exe /k " & "for /F " & """tokens=2 delims=':'""" & " %%i in ('zbarimg Test-Datei.jpg') do set String= %%i")  
(Hier ist aber noch irgendein Syntax-Fehler drin.)
Wie bekomme ich den Wert der Variable "String" zur weiteren Verarbeitung in die vbs-Datei? Vielleicht macht es auch mehr Sinn nur den reinen Programmaufruf ('zbarimg Test-Datei.jpg')an die Kommandozeile zu übergeben und den Sting dann in der vbs zu "zerpflücken" um nur den Teilstring zu bekommen?

Hier zur Info noch der funktionierende Aufruf in einer Batch-Datei:
for /F "tokens=2 delims=':'" %%i in ('zbarimg "Test-Datei.jpg"') do set "String=%%i"  
echo Wert: %String%
pause

Danke schon mal im Voraus!!! face-smile
Torsten
colinardo
Lösung colinardo 19.01.2016 aktualisiert um 12:22:33 Uhr
Goto Top
Hallo Torsten,
mach das nicht so umständlich. Es gibt da eine viel cleanere Methode den Output eines DOS-Befehls in VBS abzufragen:
Set objShell = CreateObject("Wscript.Shell")  

'Befehl ausführen  
Set oExec = objShell.Exec("cmd /c zbarimg Test-Datei.jpg")  

'Warte darauf das der Befehl beendet wurde  
Do While oExec.Status = 0
     WScript.Sleep 100
Loop

' StdOut auslesen  
out = ""  
Do While Not oExec.StdOut.AtEndOfStream
   out = out & oExec.StdOut.ReadAll
Loop

' zweites Token der ersten Zeile ausgeben, Delimiter ist ":"  
MsgBox Split(out,":",-1,1)(1)  
Ich gehe hier nur einmal von einer Ausgabe-Zeile aus. Wenn die Ausgabe des Befehls anderst aussieht musst du sie hier posten dann passe ich es dir noch an.

Grüße Uwe

p.s. Diese Methode hatte ich dir hier auch schon mal gepostet face-wink
Vbs - Variable als Parameter an externes Programm übergeben und Rückgabewert in Variable schreiben
goodbytes
goodbytes 19.01.2016 um 12:24:40 Uhr
Goto Top
Hallo Uwe,
oh, sorry, stimmt, du hast es mir schon einmal gepostet... Asche auf mein Haupt... face-wink

Ich danke dir auf jeden Fall, es funktioniert jetzt bestens so!
Einen schönen Tag wünsche ich dir noch!

Gruß
Torsten
goodbytes
goodbytes 20.01.2016 um 23:53:50 Uhr
Goto Top
Bisher war ich der Meinung, dass ich von dem Tool zur Barcode-Erkennung nur einen String zurück bekomme. Nun hat sich herausgestellt, dass wenn zufällig andere Barcodes enthalten sind, diese getrennt mit einem Zeilenumbruch (vbCrlf) mit ausgegeben werden.

So also:
Code128:182883839
Code128:049483738
Code128:B2016-12345
Code128:9438375zu
Code128:E2016-12345
usw.

Nun muss ich also noch den gesamten String durchsuchen nach meinem Barcode, der mit "B20" oder "E20" beginnt suchen und nur genau diesen String "B2016-12345" bekommen. Ist bisher nicht aufgefallen, da immer nur ein Barcode vorhanden war...
Wäre auch zu einfach gewesen... Naja, was solls, mal sehen...

Gruß
Torsten
colinardo
colinardo 21.01.2016 aktualisiert um 10:13:33 Uhr
Goto Top
Auch kein Hexenwerk face-smile
Set objShell = CreateObject("Wscript.Shell")  
Set regex = CreateObject("vbscript.regexp")  
regex.IgnoreCase = True : regex.Global = True
regex.Pattern = ":((B|E)\d{4}-[^\s]+)"  
'Befehl ausführen  
Set oExec = objShell.Exec("cmd /c zbarimg Test-Datei.jpg")  

'Warte darauf das der Befehl beendet wurde  
Do While oExec.Status = 0
     WScript.Sleep 100
Loop

' StdOut auslesen  
out = ""  
Do While Not oExec.StdOut.AtEndOfStream
   out = out & oExec.StdOut.ReadAll
Loop

Set matches = regex.Execute(out)
if matches.count > 0 then
    for each match in matches
        Msgbox match.submatches(0)
    next
end if

-edit- Code etwas angepasst
goodbytes
goodbytes 21.01.2016 um 09:17:58 Uhr
Goto Top
Hallo,
eine Frage dazu. Könnte ich nicht direkt an der folgenden Stelle den Rückgabestream auf das erste Auftreten von "B20" oder "E20" prüfen und die Schleife mit dem Wert als Varialbe (wie im obigen Beispiel) "B2016-12345" oder "E2016-12345" verlassen?
Do While Not objExec.StdOut.AtEndOfStream
      out =out & objExec.StdOut.ReadAll
Loop
Wäre das nicht der schnellere Weg, statt die Ausgabe in "out" nachträglich nach einem String zu durchsuchen? Oder sehe ich da etwas falsch? Wenn es tatsächlich so wäre, wie sähe das dann aus?
Ansonsten müsste ich wohl nachträglich "out" zuerst nach "vbCrlf" splitten...
MyVar = Split(out,"vbCrlf,",-1,1)(0)  
...dann das Ergebnis nach ":" splitten...
MyVar = Split(out,":",-1,1)(1)  
...um zum Schluss zu überprüfen ob der Rest mit "B20" oder "E20" beginnt.
If UCase(Left(out,3)) = "B20" or UCase(Left(out,3) = "E20") Then ...  
Wenn es nicht zutrifft dann weiter. Es kommt mir so aber ziemlich umständlich vor... Was meint ihr dazu?

Gruß
Torsten
goodbytes
goodbytes 21.01.2016 um 09:54:09 Uhr
Goto Top
Hallo Uwe,
unsere Kommentare haben sich vorhin gerade überschnitten. Danke erstmal für deinen... face-smile
Über so einen regulären Ausdruck scheint es ja zu funktionieren. Was bedeuten die Parameter "regex.Pattern = ": (B|E)\d{4}-[^\s]+" im Detail?
Der Teil ": (B|E)" bedeutet ich suche nach dem Vorkommen ":B" oder ":E". Ist natürlich clever hier gleich den Doppelpunkt einzubringen, das erspart mir das zweite splitten. Herausfiltern kann ich den Doppelpunkt ohnehin danach dann mittels:
Replace(strFileNameNew,":","",1,-1,1)  
Der String "-[^\s]" sagt dann sicher, dass ab dem Zeilenumbruch neu verglichen werden muss? Und was bedeutet "d{4}" und "+"? Und weshalb ist es nicht möglich auf mehr Zeichen abzuprüfen, statt auf ":B" auf "B20"? Wenn ich es so mache: ": (B20|E20)\d{4}-[^\s]+" wird kein Vorkommen gefunden. Ich möchte nur weitestgehend garantieren, dass ich auch den richtigen String gefunden habe, da machen noch zwei Stellen mehr viel aus.
Sorry, wenn ich deine Zeit dafür so beanspruche, aber ich möchte es natürlich gerne verstehen, was ja auch Sinn des Forums ist... Auf jeden Fall nochmal vielen vielen Dank für deine Hilfe... face-smile

Gruß
Torsten
colinardo
Lösung colinardo 21.01.2016 aktualisiert um 11:11:40 Uhr
Goto Top
Zitat von @goodbytes:

Hallo Uwe,
unsere Kommentare haben sich vorhin gerade überschnitten. Danke erstmal für deinen... face-smile
Über so einen regulären Ausdruck scheint es ja zu funktionieren. Was bedeuten die Parameter "regex.Pattern = ": (B|E)\d{4}-[^\s]+" im Detail?
Der Teil ": (B|E)" bedeutet ich suche nach dem Vorkommen ":B" oder ":E". Ist natürlich clever hier gleich den Doppelpunkt einzubringen, das erspart mir das zweite splitten.
Korrekt, Suche nach einem Doppelpunkt gefolgt von einem E oder B
Herausfiltern kann ich den Doppelpunkt ohnehin danach dann mittels:
Das korrigiere ich oben noch mit einer Klammersetzung im Regex, hätte ich vergessen, dann ist das ausfiltern des Doppelpunktes nicht mehr nötig.
Der String "-[^\s]" sagt dann sicher, dass ab dem Zeilenumbruch neu verglichen werden muss?
Nein, das bedeutet suche nach Bindestrich gefolgt von mindestens einem Zeichen was kein unsichtbares Zeichen (Leerzeichen/Zeilenumbruch/etc.) ist, damit diese nicht im String landen.
Und was bedeutet "d{4}" und "+"?
\d{4} bedeutet suche genau nach einer Zahl und das genau 4 mal, das + ist ein Quantifizierungsoperator und sagt matche das vorherige Muster mindestens einmal, hier also "mindestens" ein Zeichen was kein unsichtbares Zeichen ist.

Und weshalb ist es nicht möglich auf mehr Zeichen abzuprüfen, statt auf ":B" auf "B20"? Wenn ich es so mache: ": (B20|E20)\d{4}-[^\s]+" wird kein Vorkommen gefunden. Ich möchte nur weitestgehend garantieren, dass ich auch den richtigen String gefunden habe, da machen noch zwei Stellen mehr viel aus.
Das ist durch meine obigen Kommentare nun erledigt...
Sorry, wenn ich deine Zeit dafür so beanspruche, aber ich möchte es natürlich gerne verstehen, was ja auch Sinn des Forums ist... Auf jeden Fall nochmal vielen vielen Dank für deine Hilfe... face-smile

Kein Problem.
Aber einmal kurz in die Regular Expression Syntax Referenz geschaut hätte dir bestimmt auch geholfen den Pattern zu verstehen face-wink

Grüße Uwe
goodbytes
goodbytes 21.01.2016 um 11:21:38 Uhr
Goto Top
Ich hab nun nochmal in die Regular Expression Syntax Referenz geschaut, da ich noch meine Probleme mit dem "\d{4}" hatte... face-wink
Jetzt ist es natürlich klar, wenn ich z.B. nach "B2016-..." suche nehme ich entweder ": ((B20|E20)\d{2}-[^\s]+)", dann prüfe ich genau auf "B20" bzw. "E20" und zwei beliebigen Zahlen und "-" ab, dagegen bei ": ((B2016|E2016)-[^\s]+)" muss die Jahreszahl komplett sein, gefolgt von einem "-".
Super, es funktioniert bestens jetzt, Danke Uwe !!! face-smile

Gruß
Torsten
colinardo
colinardo 21.01.2016 aktualisiert um 12:19:31 Uhr
Goto Top
OK schön das du es verstanden hast, wusste halt nicht wie deine Daten aussehen "könnten", aber du hast es ja schon richtig an deine Bedürfnisse angepasst, solange das Skript nicht im nächsten Jahrhundert laufen muss face-smile (ob's dann noch VBS gibt ? vielleicht im Museum face-big-smile)
goodbytes
goodbytes 22.01.2016 um 09:39:54 Uhr
Goto Top
Nun muss ich also nur noch aufpassen, dass ich am Silvesterabend am 31.12.2099 nicht noch hektisch an meinen Rechner rennen muss weil ich vergessen hab das Script auf das neue Jahrhundert umzustellen... face-wink *lach*
colinardo
colinardo 22.01.2016 aktualisiert um 10:14:19 Uhr
Goto Top
Nun muss ich also nur noch aufpassen, dass ich am Silvesterabend am 31.12.2099 nicht noch hektisch an meinen Rechner rennen muss weil ich vergessen hab das Script auf das neue Jahrhundert umzustellen... *lach*
Wenn, ja wenn dir die nette Pflegedame nicht die Feststellbremse an deinem Rollstuhl eingerastet hätte... face-big-smile face-big-smile
goodbytes
goodbytes 22.01.2016 um 10:29:25 Uhr
Goto Top
Hahaha, ja genau... face-smile face-smile face-smile *lach*