artemis
Goto Top

Per CMD: Suchen - Löschen - Bereinigen in Textdatei

Guten Tag, ich bin neu hier!

Oft schon habe ich hier begeistert mitgelesen und schon so manchen guten Code gefunden.
Jetzt aber ist es doch so speziell, daß ich selber posten will. Wenn es dafür eine Lösung gäbe, wäre das echt toll:

Eine per
dir *.* /A-D /S /OGN /B > C:\Obstlist.txt
erstellte Textdatei sieht (als Muster) beispielsweise zunächst so aus:

C:\Obst\Apfel.jpg
C:\Obst\Birne.jpg
C:\Obst\Dattel=01.jpg
C:\Obst\Dattel=02.jpg
C:\Obst\Dattel=03.jpg
C:\Obst\Dattel=04.jpg
C:\Obst\Kirsche.jpg
C:\Obst\Kiwi=Super.jpg
C:\Obst\Melone.jpg
C:\Obst\Pflaume=AAB.jpg
C:\Obst\Pflaume=AABCäsar.jpg
C:\Obst\Pflaume=Ferdinand.jpg
C:\Obst\Stachelbeere.jpg
...

und soll per cmdline (Batchbefehle)
mit diesem Ergebnis geändert werden:

C:\Obst\Apfel.jpg
C:\Obst\Birne.jpg
C:\Obst\Dattel=01.jpg
C:\Obst\Kirsche.jpg
C:\Obst\Kiwi=Super.jpg
C:\Obst\Melone.jpg
C:\Obst\Pflaume=AAB.jpg
C:\Obst\Stachelbeere.jpg
...

Beschreibung der Änderung:

Ein "=" im Dateinamen verweist auf eine fertig bearbeitete Datei mit evtl. mehreren Varianten. Zur Katalogisierung sind diese Varianten aber nicht erwünscht, sondern nur die alphabetisch jeweils erste Variante, die ein "=" enthält. Alle nachfolgenden Zeilen mit gleichem Dateinamen VOR dem "=" sollen gelöscht werden. Das Ergebnis wird wieder gespeichert unter C:\Obstlist.txt.

Das Programm sollte also dieses (oder ähnliches mit selbem Ergebnis) machen:

- Wenn in C:\Obstlist.txt
- die (alphabetisch von oben nach unten) nächste Zeile ein "=" enthält,
- dann nimm die Zeichenfolge vom Anfang dieser Zeile bis einschließlich zu dem "=",
- finde alle nachfolgenden Zeilen, die ebenso am Anfang genau diese Zeichenfolge enthalten,
- und lösche alle diese (nachfolgend gefundenen) Zeilen komplett.
- Fahre nun genauso fort mit der nächsten Zeile nach der eingangs gefundenen Zeile...
- Wenn fertig, speicheren.

Wie lautet der Batch-cmd-Code (Formel) für diese Aufgabe?
Warum? Der Job ist immer wieder zur Aktualisierung bei großen Dateilisten zu machen.

Vielen Dank!

Artemis

Content-Key: 293871

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

Printed on: April 25, 2024 at 20:04 o'clock

Member: Friemler
Solution Friemler Jan 22, 2016, updated at Feb 11, 2016 at 16:38:06 (UTC)
Goto Top
Hallo Artemis,

teste mal folgendes:
@echo off & setlocal

set "InFile=.\ObstListe.txt"  
set "OutFile=.\ObstListe.txt"  
set "TmpFile=%TEMP%\FilteredFileList.txt"  

set "LastFile="  

(for /f "usebackq tokens=* delims=" %%a in ("%InFile%") do (  
  for /f "tokens=1* delims==" %%b in ("%%~na") do (  
    call :ProcessFile "%%~dpa" "%%b" "%%~xa" "%%c"  
  )
)) > "%TmpFile%"  

move "%TmpFile%" "%OutFile%" > NUL  

exit /b 0



:ProcessFile
  if "%~2" neq "%LastFile%" (  
    if "%~4" equ "" (  
      echo %~1%~2%~3
    ) else (
      echo %~1%~2=%~4%~3
    )
  )

  set "LastFile=%~2"  
exit /b 0

Gruß
Friemler
Member: Artemis
Artemis Feb 03, 2016 updated at 09:04:01 (UTC)
Goto Top
Hallo Friemler,

vielen Dank für dieses Script, leider habe ich es noch nicht zum Laufen bekommen. Ich habe mit dieser Batch getestet:

@echo off & setlocal 

dir *.* /A-D /S /OGN /B > C:\Katalog\HDD-1.txt
pause

set "InFile=C:\Katalog\HDD-1.txt"   
set "OutFile=C:\Katalog\HDD-1.txt"   
set "TmpFile=%TEMP%\FilteredFileList.txt"   

set "LastFile="   

(for /f "usebackq tokens=* delims=" %%a in ("%InFile%") do (   
  for /f "delims==" %%b in ("%%~na") do (   
    call :ProcessFile "%%~dpa" "%%b" "%%~xa"   
  ) 
)) > "%TmpFile%"   
 
move "%TmpFile%" "%OutFile%" > NUL   
 
exit /b 0 
 
:ProcessFile 
  if "%~2" neq "%LastFile%" (   
    echo %~1%~2%~3 
  ) 
 
  set "LastFile=%~2"   
exit /b 0

Da mir dieses Skript etwas "zu hoch" ist, um den Ablauf tatsächlich zu verstehen, war es mir auch nicht möglich, ein "pause" verschiedentlich in Hauptcode oder Subroutine zu platzieren, um letztlich den Fehler auszutesten.

Ich vermute zunächst einen Schreibfehler bei meinen Pfadangaben. Was genau heißt ".\" vor dem Dateinamen? Mit meiner dir-Zeile wird anfangs die HDD-1.txt richtig erstellt, aber dann nicht mehr geändert. Wenn ich ganz genau achtgebe, blitzt irgendwas mit "nicht gefunden" raus.

Ich bitte nochmal um Hilfe oder eine Anleitung zur Fehlereingrenzung.

Artemis

[Edit Biber] Codeformatierung ergänzt. [/Edit]
Member: Friemler
Solution Friemler Feb 03, 2016, updated at Feb 11, 2016 at 16:38:16 (UTC)
Goto Top
Hallo Artemis,

als erstes fällt mir auf, dass Du eine veraltete Version des Scripts verwendest, die Deine Anforderungen nicht erfüllt. Kopiere Dir bitte den aktuellen Quelltext.

Zum Debuggen von Batchscripten sollte man

  1. diese immer aus einem Konsolenfenster starten und nicht per Doppelklick.
  2. das @echo off in der ersten Zeile entfernen oder durch :: bzw. REM auskommentieren, dabei aber das setlocal in eine neue Zeile schreiben, damit es weiterhin ausgeführt wird.

Dann sieht man die ausgegebenen Fehlermeldungen und kann außerdem den Scriptlauf verfolgen, d.h. man kennt die Stelle, an der das Script beendet wird.

Es könnte auch nützlich sein, den tatsächlichen Pfad zu Deiner HD-1.txt zu kennen, evtl. enthält er irgendwelche Sonderzeichen, die das Script "verwirren". Auf jeden Fall wäre es eine gute Idee, bei Deinem DIR-Befehl den Pfad zur Ausgabedatei in Anführungszeichen zu setzen, dann können darin enthaltene Sonder- und Leerzeichen an dieser Stelle schon nicht mehr stören.

Zu Deiner Frage: ".\" ist eine Abkürzung für "Das aktuelle Verzeichnis".

Bei mir hier laufen übrigens beide Versionen des Scripts fehlerfrei.

Gruß
Friemler
Member: Artemis
Artemis Feb 04, 2016 at 02:29:34 (UTC)
Goto Top
Hallo Friemler,

danke für die Tipps. Das mit dem Konsolenfenster und dem Einschalten von Echo weiß ich normalerweise, habe aber diesmal vergessen dranzudenken, weil ich mich zu sehr auf meine Verzeichnisse im TotalCommander konzentriert habe und solche Analysen eben (nicht mehr) so häufig mache.

Aber wir sind jetzt schon ein Stück weiter. Das Script funktioniert im Prinzip (wenn.. dann..), hat aber wohl noch einen typischen Rückabsicherungsfehler (wenn aber..). Deckt also noch nicht alle denkbaren Ausnahmen oder Eventualitäten ab, die in einem Datei- bzw. Verzeichnissystem vorkommen können (Sonderzeichen oder spezielle Buchstabenkombintionen) und fliegt dann ersatzlos aus der Kurve. Möglicherweise ist es auch überfordert, wenn es nix zum Beißen findet, wenn also überhaupt kein "=" in einem Dateinamen vorkommt.

Der Reihe nach:

Aktualisiert (danke für die zwischenzeitliche Überarbeitung!) habe ich so getestet:

back-to-topq.bat ++++++++++++++++++++++++++++++


@echo off & setlocal

dir *.* /A-D /S /OGN /B > C:\HDD-1.txt

set "InFile=C:\HDD-1.txt"
set "OutFile=C:\HDD-1.txt"
set "TmpFile=%TEMP%\FilteredFileList.txt"

set "LastFile="

(for /f "usebackq tokens=* delims=" %%a in ("%InFile%") do (
for /f "tokens=1* delims==" %%b in ("%%~na") do (
call :ProcessFile "%%~dpa" "%%b" "%%~xa" "%%c"
)
)) > "%TmpFile%"

move "%TmpFile%" "%OutFile%" > NUL

exit /b 0


:ProcessFile
if "%~2" neq "%LastFile%" (
if "%~4" equ "" (
echo %~1%~2%~3
) else (
echo %~1%~2=%~4%~3
)
)

set "LastFile=%~2"
exit /b 0


Diese q.bat steht in meinem Batch-Sammlungsverzeichnis, das systemweit per path= eingebunden ist.
Per TotalCommander wähle ich ein x-beliebiges Verzeichnis (mit oder ohne subs) und starte dort die Konsole zwecks Sicht (oder auch nicht, ist für die Funktion ja egal). Es geht/muß natürlich auch über direkte Pfadeinstellungen innerhalb des Scripts gehen, ist jetzt nicht das Thema, geht allemal, logisch.

Ich experimentierte mit diesen beiden Varianten und diversen Kombinationen:

Var.1: das *.* hinter dem dir, also beispielsweise: dir *.* - dir *.txt - dir.wmv - dir.wmv dir.mp4 dir.avi - dir *.tif dir *.bmp

Var 2: Wechsel des Verzeichnisses, und somit andere Dateiendungen und evtl. andere neue Ausnahmezeichen oder Pfade, oder auch mal Durchläufe ganz ohne "="

Die Ergebnisse / Fehlermeldungen in der Konsole sind immer wieder anders, ohne erkennbares Muster, z.B.

".mp4" kann syntaktisch an dieser Stelle nicht verarbeitet werden.
oder
".avi" kann syntaktisch an dieser Stelle nicht verarbeitet werden.

In einem anderen Verzeichnis hingegen wird .mp4 ohne Mecker verarbeitet, dafür gibts beispielsweise Probleme mit *.wmv.
Änderungen des Jokers bringen andere Ergebnisse, manchmal auch ohne Fehlermeldung. Dann macht das Skript genau das, was es soll.
Aber Verzeichnise bzw. Aufträge, in denen kein "=" vorkommt, wo also nichts zu tun ist, fabrizieren immer einen Mecker verschiedenster Art, Beispiele:

Beispiel Fehlermeldung Auftrag 1:
Der Befehl "Lines.txt" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
FEHLER: Ungültige Syntax. Die Standardoption darf nicht mehr als 1 Mal verwendet
Geben Sie "TIMEOUT /?" ein, um die Syntax anzuzeigen.
Der Befehl "Shell" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
Der Befehl "IT" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
".mht" kann syntaktisch an dieser Stelle nicht verarbeitet werden.

Beispiel Fehlermeldung Auftrag 2:
Das System kann den angegebenen Pfad nicht finden.
"\wrar390.exe" kann syntaktisch an dieser Stelle nicht verarbeitet werden.

Beispiel Fehlermeldung Auftrag 3:
Der Befehl "Lines.txt" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
"\WinRAR.txt" kann syntaktisch an dieser Stelle nicht verarbeitet werden.


echo on-Beispiel mit *.* :
(Kopie der Konsolenausgabe)

F:\Archiv>q

F:\Archiv>dir *.* /A-D /S /OGN /B 1>C:\HDD-1.txt

F:\Archiv>set "InFile=C:\HDD-1.txt"

F:\Archiv>set "OutFile=C:\HDD-1.txt"

F:\Archiv>set "TmpFile=C:\Users\Kobold\AppData\Local\Temp\FilteredFileList.txt"

F:\Archiv>set "LastFile="

F:\Archiv>(for /F "usebackq tokens=* delims=" %a in ("C:\HDD-1.txt") do (for /F "tokens=1* delims==" %b in ("%~na") do (call :ProcessFile "%
~dpa" "%b" "%~xa" "%c" ) ) ) 1>"C:\Users\Kobold\AppData\Local\Temp\FilteredFileList.txt"
Der Befehl "Lines.txt" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
FEHLER: Ungültige Syntax. Die Standardoption darf nicht mehr als 1 Mal verwendet werden.
Geben Sie "TIMEOUT /?" ein, um die Syntax anzuzeigen.
Der Befehl "Shell" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
Der Befehl "IT" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
".mht" kann syntaktisch an dieser Stelle nicht verarbeitet werden.

F:\Archiv>


Gleiches Verzeichnis, aber *.zip :
(hier %TEMP% mit einem einfachen konkreten Pfad ersetzt, ist aber offensichtlich egal)

F:\ARCHIV>q

F:\ARCHIV>dir *.zip /A-D /S /OGN /B 1>C:\HDD-1.txt

F:\ARCHIV>set "InFile=C:\HDD-1.txt"

F:\ARCHIV>set "OutFile=C:\HDD-1.txt"

F:\ARCHIV>set "TmpFile=C:\TempoX.txt"

F:\ARCHIV>set "LastFile="

F:\ARCHIV>(for /F "usebackq tokens=* delims=" %a in ("C:\HDD-1.txt") do (for /F "tokens=1* delims==" %b in ("%~na") do (call :ProcessFile "%
~dpa" "%b" "%~xa" "%c" ) ) ) 1>"C:\TempoX.txt"
Das System kann den angegebenen Pfad nicht finden.
Das System kann den angegebenen Pfad nicht finden.
Das System kann den angegebenen Pfad nicht finden.
Das System kann den angegebenen Pfad nicht finden.
Das System kann den angegebenen Pfad nicht finden.
Das System kann den angegebenen Pfad nicht finden.
"_634141074586133750.zip" kann syntaktisch an dieser Stelle nicht verarbeitet werden.

F:\ARCHIV>

Auffällig: die Fehler kommen immer nach dem Schreiben in die Temp-file.

Es geht wie Kraut und Rüben und ohne Logik, aber je einfacher ich die Varianten (Joker + Verz.-Wahl) halte, desto häufiger bekomme ich go-Treffer = fehlerfreie + richtige Verarbeitung.

Zusammenfassung

Script funktioniert, ist aber bzgl. möglicher Sonderfälle und Ausnahmen noch nicht wasserdicht. Es soll auf einem NTFS-W7-Rechner systemweit (für jedes Verzeichnis, unabhängig der Zeichen, alles was NTFS erlaubt) funktionieren. Ich vermute, das Problem ist nur eine Winzigkeit und schon passt es..

Schön wäre es außerdem, wenn es bzgl. des Suchparameters (momentan "=") flexibel einsetzbar wäre. Wenn ich also anstelle "=" als Killerkriterium beispielsweise "f}Tür\ß_%" einsetze (austausche), dann soll es eben damit laufen. Dazu wäre es wohl am besten, wenn ich nicht jedesmal fehlerträchtig alle Stellen mit "=" suchen und ersetzen müßte (delims==" ist dann bereits so ne Sache...), sondern wenn das Suchkriterium besser eingangs bei den sets 1x klar in "Gänsefüßchen" definiert wird, und gut is.

Danke für die Geduld!

Artemis
Member: Artemis
Artemis Feb 04, 2016 at 03:34:05 (UTC)
Goto Top
...rummachen, rummachen,
und jetzt bin ich noch ein Stück weiter:

Das "&" in den Dateinamen macht Probleme, an diesen Stellen wird offensichtlich immer der Prog-Ablauf beendet, weil "&" ein Befehlszeichen ist.
Das betrifft wohl alle Meldungen, auch die Suffix-Meldungen wie diese hier:
".mht" kann syntaktisch an dieser Stelle nicht verarbeitet werden

Denn wenn ich testhalber alle mht´s aus dem Verz. entferne, dann kommt wieder eine Klartext-Namenmeldung.
Suche ich dann im Verz. danach, siehe da: wieder ein Dateiname, der ein "&" enthält.

Es ist also immer nur das "&" schuld, nie die Suffixe.

Durch testhalber umbenennen ("&" weggemacht) konnte ich den Fehler komplett eliminieren.
Was aber nicht Sinn der Sache ist. Da fehlen wohl die rechten "Gänsefüßchen" an den richtigen Stellen im Skript.

Ich wüßte auch nicht, wo sonst noch irgendwelche Pfad-"Gänsefüßchen" fehlen könnten.
Auch eine Codeseiten-Änderung wie:

chcp 1252
dir *.* ...usw.
chcp 850
..weiter im Script

bringt - zumindest so - nichts (hat mir aber in einem anderen Script bei einem ähnlichen Problem geholfen)

Bitte also um ein Script im Script für "&" face-wink
Member: Artemis
Artemis Feb 04, 2016 at 04:14:16 (UTC)
Goto Top
...und doch noch was:

Klammern, also "(" und/oder ")" im Dateinamen, sind bei diesem Script ebenso extrem unbeliebt, verursachen genauso wie "&" sofortigen Totalschaden.

Wie 2 Häuschen weiter oben am Ende schon gesagt: Das Skript braucht funktionstechnische Unabhängigkeit von allen Sonderzeichen.
Es muß als Futter ALLE DIE Zeichen verarbeiten können, die NTFS bei den Namen im Dateisystem erlaubt.
Auch alle die komischen Zeichen, von denen ich heute noch nicht mal eine Ahnung habe, daß es sie überhaupt gibt und die morgen erst in
meinem System vorkommen werden, ohne daß ich es weiß, weil meine chinesische Freundin angefangen hast, in den Dateinamen rumzumalen face-smile

Will heißen: Zähne und Futter sollen unabhängig voneinander funktionieren, auch wenn´s mal nicht schmeckt. Dann halt mit ÄhBäh ausspucken und weiter zum nächsten, aber net jedesmal gleich eine Kreislaufstörung kriegen.

Schnaps bleibt Schnaps, und... ach was...

(So geblühmt klingt es, wenn es bereits morgens um 5 ist...)

Artemis
Member: Friemler
Solution Friemler Feb 04, 2016, updated at Feb 11, 2016 at 16:38:33 (UTC)
Goto Top
Hallo Artemis,

jo, evtl. solltest Du mal 'ne Mütze Schlaf nehmen, so viel Aufregung ist das nicht wert. face-wink

Das ist ein klassischer Fall von zu einfach strukturierten Beispieldaten. Die Ausgaberoutine, das Unterprogramm ProcessFile, ist in ihrer obigen Form mit Dateinamen, die bestimmte Sonderzeichen enthalten, einfach überfordert - wir hantieren hier eben mit Batchscript, das nur sehr bedingt für die Verarbeitung von Text geeignet ist (und der Interpreter wurde wahrscheinlich von einem Redmonder Praktikanten geschrieben).

Eine erste Entschärfung des Problems wäre folgendes:
@echo off & setlocal

:: ******* Begin Config *********
set "FileMask=*.txt"  
set "Delim=="  

set "InFile=C:\Katalog\HDD-1.txt"  
set "OutFile=%InFile%"  
:: ******** End Config **********


:: ----------- Init -------------
set "TmpFile=%TEMP%\FilteredFileList.txt"  
set "LastFile="  

:: Arbeitsverzeichnis setzen
if "%~1" neq "" cd /d "%~1"  

:: Inhalt der evtl. bereits existierenden
:: temporären Datei löschen
type NUL > "%TmpFile%"  

:: Codepage auf ANSI umschalten
chcp 1252 > NUL


:: ----------- Main -------------
:: Dateiliste erstellen
for %%a in ("%CD%") do (  
  if "%%~na" equ "" (  
    dir "%%~a%FileMask%" /s /b /a:-d /o:gne 2>NUL 1>"%InFile%"  
  ) else (
    dir "%%~a\%FileMask%" /s /b /a:-d /o:gne 2>NUL 1>"%InFile%"  
  )
)


:: Dateiliste verarbeiten
(for /f "usebackq tokens=* delims=" %%a in ("%InFile%") do (  
  for /f "tokens=1* delims=%Delim%" %%b in ("%%~na") do (  
    call :ProcessFileName
  )
)) > "%TmpFile%"  


:: Ausgabedatei erzeugen
move "%TmpFile%" "%OutFile%" > NUL  


:: Script Ende
exit /b 0



:: -------- Unterprogramme ---------
:ProcessFileName
  for /l %%x in (1,1,1) do (
    if "%%b" neq "%LastFile%" (  
      if "%%c" equ "" (  
        echo %%~dpa%%b%%~xa
      ) else (
        echo %%~dpa%%b%Delim%%%c%%~xa
      )
    )

    set "LastFile=%%b"  
  )
exit /b 0

Diese neue Version sollte mit sämtlichen abstrusen Zeichen in Dateinamen umgehen können.

In Zeile 4 kannst Du eine Dateimaske und in Zeile 5 das Trennzeichen einstellen.

Du kannst entweder eine Konsole in einem bestimmten Verzeichnis öffnen und von dort das Script starten (wird bei Dir ja über die PATH-Variable gefunden) oder dem Script ein Verzeichnis als Parameter übergeben bzw. per Drag&Drop ein Verzeichnis auf dem Icon des Scripts "ablegen", das dann zum aktuellen Verzeichnis gemacht wird. In allen Fällen sucht das Script im dann aktuellen Verzeichnis nach Dateien, auf die die o.g. Maske passt. Damit es egal ist, ob es sich beim aktuellen Verzeichnis um das Wurzelverzeichnis eines Laufwerks oder um irgendein Unterverzeichnis handelt, habe ich die Konstruktion in den Zeilen 29 bis 35 eingebaut.

Das Script schaltet die verwendete Codepage in Zeile 24 auf ANSI um, damit normale Texteditoren und andere Programme in der erzeugten Ausgabedatei enthaltene deutsche Umlaute richtig darstellen bzw. lesen können. Falls Du die Ausgabedatei mit Batchscript weiterverarbeiten möchtest, musst Du Zeile 24 auskommentieren.

Deine neue Anforderung nach beliebigen Trennzeichen statt dem = lässt sich nicht so einfach erfüllen. Der Tokenizer der FOR-Schleife behandelt eine Zeichenkette hinter delims= als Liste von Trennzeichen. Bei delims=äß% wären also ä, ß und % jeweils für sich alleine Trennzeichen, der Dateiname abcädef%ghißjkl.txt würde also zerlegt zu abc, def, ghi und jkl.txt. Wenn Du als Trennzeichen irgendein chinesisches Zeichen angeben möchtest, wird das wahrscheinlich nicht funktionieren, da Du den Quelltext des Batchscripts (auf einem deutschen Windows) codiert mit der Codepage 850 abspeichern musst bzw. der Interpreter setzt dies voraus. Die Codepage 850 enthält aber keine chinesischen Zeichen, somit kannst Du diese auch nicht als Trennzeichen in den Quelltext eintragen. Sollte das eine wichtige Anforderung sein, kann man Batchscript nicht zur Lösung Deines Problems verwenden.

Gruß
Friemler
Member: Artemis
Artemis Feb 05, 2016 at 05:04:29 (UTC)
Goto Top
Hallo Friemler,

danke der Fürsorge, aber bin eh ein Nachtlicht face-wink Und ausnahmsweise bin ich halt bei diesem Projekt mal "dabei geblieben". Viel zu vieles ist oft schon wegen "so viel Aufregung ist das nicht wert" vorübergehend liebengeblieben - und liegt heute noch.

Generelle Frage zum Forum-/ScriptHandling: Mein einkopiertes Script wurde nachträglich von Biber "in Form" gebracht. Hätte ich das selber tun sollen? Wie/wo steht/geht das? Andersherum: zum Besprechen ist das ja sehr praktisch und übersichtlich. Aber zum Anwenden muß ich erst kopieren, und dann aber (mühsam und fehlerträchtig) die ganzen Zeilenziffern und Leerzeichen zu Fuß löschen, damit das dann ein batchiges Gesicht bekommt. Oder wie wird das hier gehandhabt? Gibt es evtl. einen Geheimknopf, der mir Deinen Entwurf anwendungsgerecht runterlädt? Nur so eine Idee ...

Zum Thema:
Hab das neue jetzt noch nicht "runtergeladen" und getestet. Erst mal: danke! - und etwas Theorie vorab zu den Begriffen:
"Chinesische Zeichen" will ich ganz sicher nicht verwenden, und es gibt hier auch keine chinesische Freundin. Das war doch nur ein Scherz in der Verzweiflung des Gefechts!

Trennzeichen? Möglicherweise läßt sich die Sache ja mit einigermaßen vernünftigen Aufwand realisieren, wenn dieses "=" als Trennzeichen behandelt wird, wie du ja sehr schön erklärt hast. Ich hab das nie als Trennzeichen (um irgendwas zu trennen) gesehen, sondern als "Erkennungszeichen". Noch besser: als "Markierung" für die Dateien, die bereits... ja egal was: schon bearbeitet sind, oder irgendwie sonst sortiert oder klassifiziert werden. Da liegt es dann nahe, sich das Script zumindest so universell (variabel) zu wünschen, daß auch mal mehrere Klasssen von Dateien organisiert werden wollen. Ist sowas wie die W7-Bibliotheken (die ich aber gar nicht mag, weil ich zuwenig direkten Kontakt, auch über Script, halten kann). Natürlich - auch hier kein komisches Zeichenzeugs, aber z.B. "==" oder "=1" "=2" ... oder auch nur ein einfacher einstelliger Austausch im Sinne eines Trennzeichens: "_" oder "$" ...
Da würd ich mich ganz nach dem machbaren richten.

Aber vielleicht bringt dich dieser Aspekt auf eine andere Sichtweise als "Trennzeichen". Statt dessen - sehr gebräuchlich im Batch - Suche nach "Zeichenkette". Evtl. wäre das ein rettend kehrtwendiger Ausweg, der alles stark vereinfacht? Ist nur eine Idee, weil ich über diese Trennzeichen-Geschichte so verwundert war. Da soll nix getrennt werden, es ist eine Notiz, eine Zeichenkette, nach der auch wieder per Script (coming soon face-smile gefandet werden könnte, um ein bestimmtes Happening in Gang zu setzen, beispielsweise.

Ansonsten... getestet wird morgen.

Gut nacht!

Artemis
Member: BirdyB
Solution BirdyB Feb 05, 2016, updated at Feb 11, 2016 at 16:38:45 (UTC)
Goto Top
Zitat von @Artemis:

Generelle Frage zum Forum-/ScriptHandling: Mein einkopiertes Script wurde nachträglich von Biber "in Form" gebracht. Hätte ich das selber tun sollen? Wie/wo steht/geht das? Andersherum: zum Besprechen ist das ja sehr praktisch und übersichtlich. Aber zum Anwenden muß ich erst kopieren, und dann aber (mühsam und fehlerträchtig) die ganzen Zeilenziffern und Leerzeichen zu Fuß löschen, damit das dann ein batchiges Gesicht bekommt. Oder wie wird das hier gehandhabt? Gibt es evtl. einen Geheimknopf, der mir Deinen Entwurf anwendungsgerecht runterlädt? Nur so eine Idee ...

Du hast schon ganz oben im Codebereich mal auf "Quelltext" geklickt, oder?

Und wenn du mal hier: How to correctly ask a question nachliest, wirst du feststellen, dass es schon wünschenswert wäre, wenn du deine Beiträge entsprechend formatierst.

Beste Grüße!
Member: Artemis
Artemis Feb 05, 2016 at 16:21:57 (UTC)
Goto Top
Hallo BirdyB,

vielen Dank für die Hinweise und Links zur Beitragsgestaltung! Sehr nützlich.

Ja, auf "Quelltext" hatte ich schon geklickt, aber nichts ist passiert. Jetzt klar: Das ist ein 2. Fenster, aber Popups sind in meinem Browser generell deaktiviert, ich öffne Links immer mit Mausgeste per copy+open. Dadurch hat man viel mehr Ruhe vor nerviger Werbung. "Quelltext" sah für ich nach einer Seiten-Umschaltung aus, die halt nicht funktioniert hat, aber nicht nach einem Popup.

Artemis
Member: Artemis
Artemis Feb 05, 2016 at 19:59:59 (UTC)
Goto Top
Hallo Friemler,

bravo, das Script läuft jetzt fehlerfrei und macht was es soll ! (...nachdem ich mit der Dateimaske in Zeile 4 einiges Stirnrunzeln verbracht habe.)

Die Dateimaske ist jetzt vom eigentlichen dir-Befehl ausgekoppelt (Zeile 4), weil das Erstellen der Dateiliste nun mit 2 Durchgängen gemacht wird. Der Unterschied ist der \ nach dem a in Zeile 33. Was genau bedeutet das?

Warum frag ich das?

Die Dateimaske in Zeile 4 hat zunächst nur eindimensional funktioniert, also *.* oder *.txt oder *.jpg
Sobald mehrere Paramater genannt wurden, wie beispielsweise:

04. set "FileMask=*.jpg *.bmp *.tif *.png"

passierte nichts mehr. Wichtig ist das, um differenzierte Kataloge erstellen zu können, z.B. nur Bilder.
Über ein Weilchen kam ich dann auf die glorreiche Idee, diese Masken nochmal eigens in "Gänsefüßchen" zu setzen, also so:

04. set "FileMask="*.jpg *.bmp *.tif *.png""

und Bingo: alles läuft jetzt wunschgemäß! Vielen Dank!

Was das "Trennzeichen" anbelangt, so funktioniert es im einstelligen Bereich mit ziemlich vielen "komischen" Zeichen, außer: % & °
Das sollte also für weitere Katalogisierungswut vorerst genügen.

Frage nur noch interessehalber: Was genau macht der Unterschied zw. Zeile 31 "a" und Zeile 33 "a\" ?
Vermutliche Antwort: Ein Wurzelverzeichnis hat keinen extra Dateinamen, also keinen "Text" zum Verarbeiten, was dem Script mit dem "\" mitgeteilt wird?

Gruß, Artemis
Member: Friemler
Friemler Feb 05, 2016 updated at 22:37:37 (UTC)
Goto Top
Hallo Artemis,

freut mich, das Du etwas hast, mit dem Du arbeiten kannst. Deine Lösung mit den multiplen Dateimasken ist sehr interessant, diese Möglichkeit kannte ich auch noch nicht, zumindest nicht in der Form, dass bei jeder Maske immer der Pfad, der vor der ersten Maske angegeben wurde, verwendet wird.


Zu Deinen Fragen:

Die Dateiliste wird entweder mit der einen Methode (Zeile 31) oder mit der anderen (Zeile 33) erstellt. Zeile 31 wird in dem Fall benutzt, wenn das Arbeitsverzeichnis des Scripts das Wurzelverzeichnis eines Laufwerks ist. Ein
dir "E:\\*.txt"
(was das Ergebnis von Zeile 33 in diesem Fall wäre) führt zu einer Fehlermeldung und zum Script-Abbruch. Deshalb fehlt in Zeile 31 der händisch hinzugefügte Backslash.


OK, das mit dem Trennzeichen hätte ich erklären müssen. Um zu erkennen, ob eine Datei in die Ausgabeliste aufgenommen werden soll, muss, laut Deiner Anforderung, der Namensteil vor dem Gleichheitszeichen/Trennzeichen der aktuellen Datei mit dem entsprechenden Namensteil der vorhergehenden Datei verglichen werden. Bei Ungleichheit wird die Datei in die Ausgabeliste aufgenommen.

Für das Splitting des Dateinamens dient die FOR-Schleife in den Zeilen 40 bis 42. Diese Form der FOR-Schleife (mit dem Parameter /f) kann dazu benutzt werden, Zeichenketten anhand eines Trennzeichens bzw. einer Liste von Trennzeichen in sog. Tokens zu zerlegen (siehe dazu auch mein Tutorial zur FOR-Schleife).

Dieses Splitting per FOR-Schleife ist in Batchscript die einzige Methode, bei der man den Dateinamen nicht in eine "normale" Batchscript-Variable (mit %-Zeichen am Anfang und Ende, z.B. %FileMask%) umspeichern muss. Denn nur beim Verarbeiten von FOR-Laufvariablen (mit zwei %%-Zeichen am Anfang, z.B. %%a) wird der Inhalt der Variable nicht interpretiert. D.h. nur so lassen sich Deine Dateinamen mit Sonderzeichen verarbeiten und ausgeben. Deswegen habe ich im Unterprogramm ProcessFileName nochmal eine FOR-Schleife (for /l %%x in (1,1,1) do..., läuft genau einmal durch) um die Vergleichs- und Ausgabebefehle "drumherum gewickelt". Durch diesen Trick kann ich die Laufvariablen der FOR-Schleifen aus dem Hauptprogramm auch im Unterprogramm verwenden und die Probleme der ersten Script-Version lösen.

Das Problem ist also: Ohne das Splitting des Dateinamens per FOR-Schleife lässt sich in Batchscript keine Lösung für Dein Problem finden. Daraus erwächst die Beschränkung, dass man nur eine einstellige Zeichenkette als Trennmarkierung definieren kann. Außerdem gelten für das Trennzeichen die üblichen Einschränkungen von Batchscript - es darf sich nicht um ein Zeichen handeln, das als Operator oder Befehl interpretiert werden kann, also zum Sprachumfang von Batchscript gehört (die Zeichen &% hast Du ja selbst schon als solche identifiziert). Zugegeben, als Batchneuling hat man natürlich keine Ahnung, welche Zeichen das sein könnten, das musst Du eben durch Ausprobieren herausfinden.

Ich denke mal, damit sind wir am Ende der Fahnenstange, besser geht es nicht mit Batchscript. Das ist sowieso schon mehr als das, wozu es eigentlich gedacht ist: Die Automatisierung von regelmäßig wiederkehrenden Aufgaben. Die Verarbeitung von Text war wohl eher nicht geplant.

Gruß
Friemler


[EDIT]
Btr. Trennzeichen: Bei Zeichen wie & könntest Du versuchen, sie zu "escapen", d.h. ein ^ voranzustellen. => aus & wird ^&
[/EDIT]
Member: Artemis
Artemis Feb 06, 2016 at 04:08:35 (UTC)
Goto Top
Hallo Friemler,

danke für die ausführliche Erläuterung, bei der ich im Mittelteil allerdings leicht ausgestiegen bin, da konnte ich mit dem FOR-Schleifen-Profi vom Dienst einfach nicht mithalten face-wink

Alles wäre wohl so gut gewesen, aber dann bin ich bei Deinem allerletzten Satz gewaltig gestolpert: "Die Verarbeitung von Text war wohl eher nicht geplant." Watdenndatdenn? Genau diese Textverarbeitung war geplant, und sonst gar nichts. Keinerlei Dateimanagement, da die vom (externen) Befehl DIR erstellte TXT mit den Pfaden+Dateien bereits fertig vorliegt und dann eben von dem Script lt. Auftrag bearbeitet werden soll. Siehe Aufgabenstellung ganz oben:

Eine per
dir *.* /A-D /S /OGN /B > C:\Obstlist.txt
erstellte Textdatei...

Aber der Reihe nach:

Zwischenzeitlich habe ich das Script für den gedachten Einsatz zurechtgestutzt und eingebaut. Es ist einer von vielen bereits existierenden Teilen einer sehr viel größeren Batch-Routine, die ab und an turnusmäßig abgearbeitet wird und geht nun so:

@echo off & setlocal

set "Delim=="  
:set "Delim=#" 
:set "Delim=@" 
:set "Delim={" 

set "InFile=%1"  
set "OutFile=%InFile%"  
set "TmpFile=C:\123.txt"  
set "LastFile="  

type NUL > "%TmpFile%"  
chcp 1252 > NUL

(for /f "usebackq tokens=* delims=" %%a in (%1) do (  
  for /f "tokens=1* delims=%Delim%" %%b in ("%%~na") do (  
    call :ProcessFileName
  )
)) > "%TmpFile%"  

move "%TmpFile%" "%OutFile%" > NUL  
exit /b 0

:ProcessFileName
  for /l %%x in (1,1,1) do (
    if "%%b" neq "%LastFile%" (  
      if "%%c" equ "" (  
        echo %%~dpa%%b%%~xa
      ) else (
        echo %%~dpa%%b%Delim%%%c%%~xa
      )
    )

    set "LastFile=%%b"  
  )
exit /b 0


Aufgerufen wird es 3x als "RedunDel.bat" per übergeordneter Mutter-Batch, nachdem per DIR die nötigen Dateilisten erstellt wurden, und zwar so:

...

REM Redundante Bearbeitungsvarianten löschen
call redundel F:\Video.!!!
call redundel F:\Audio.!!!
call redundel G:\Grafik.!!!

...

*.!!! sind bei mir Textfiles für besondere Einsatzbereiche.

Funktioniert perfekt, dauert allerdings trotz schnellem Rechner, SDD etc. vergleichsweise lange, weil das Skript möglicherweise mehr macht als es müßte, es arbeitet wohl teils nutzlos, weil es glaubt, dateisystem-intelligent handeln zu müssen (das ist diese doppeltgemoppelte Sache mit dem a und a\), anstelle sich nur auf die gefragte Textverarbeitung zu konzentrieren.

Textverarbeitung. So wie wenn ich die Files mit dem Editor öffnen würde und händisch nach "=" suche. Da ist es auch völlig wurscht, wie der Pfad vorher aussieht, oder ob er in chinesisch dasteht. (Für edit in chinesisch haben die chinesischen Windows-Rechner dieser Welt - und da gibt wohl es ein paar - vermutlich per chcp die rechte Codeseite eingestellt, passende Tastatur dazu, und schon macht unser Editor das...)

Ist das "=" dann gefunden, wo auch immer auf der Welt, dann einfach Routine lt. Auftrag abarbeiten und weiter zum nächsten "="
Es ist völlig egal, ob vor dem "=" ein Dateipfad steht, Wurzelverzeichnis hin oder her, oder ob da nur "Grüatzi beinand" hingekritzelt wurde.

Mahlzeit und Gut Nacht!!!$%&/.....=blablabla

funktioniert dann genauso. Text is Text. Und Suche ist Suche.
Ja! Ich habs gehört: Diese Scripte sind nur bedingt für Textverarbeitung geeignet, der Redmonder Lehrling...

Aber ich glaube, daß wir uns im Laufe ver Bearbeitung etwas mißverstanden haben. Du bist mir zu sehr ins Dateimanagement abgerutscht, und ich habs erst gemerkt, als ich das Script für meinen tatsächlichen Einsatz angepasst habe.

Fazit/Frage:

Könnte es sein, daß das tatsächlich erforderliche Script, vom Standpunkt reiner Textverarbeitung her,

1. anders
2. einfacher
3. somit schneller
4. zeichen-universeller (komplett NTFS /1252-kompatibel)

werden könnte und außerdem

5. sogar als Suchparameter beliebige Zeichenfolgen akzeptiert, z. B "=2=" ?

Nur Text! Kein Dateimanagement, Rootverz. und den ganzen Kram...

Sorry, das ist jetzt Perfektionissmus, aber ich schätze, Dir macht das genauso viel Spaß, wie mir?
Falls aber nicht: Danke für alles, es läuft ja jetzt schon perfekt, wie oben abgedruckt.

Artemis
Member: Artemis
Artemis Feb 06, 2016 at 05:01:28 (UTC)
Goto Top
Tschuldigung, für: "das ist diese doppeltgemoppelte Sache mit dem a und a\"
Das hat sich insofern bereits erledigt, weil ich den ursprünglichen Abschnitt ":: Dateiliste erstellen" ja selbst bereits eliminiert habe.

[Ich wollte das als "edit" in meinem vorherigen Absatz einfügen, habe aber trotz intensiver Suche nirgends eine Anleitung oder Button gefunden, wie ich meinen eigenen Beitrag nachträglich editieren kann. Wäre nett, wenn mir das jemand sagen könnte, danke!]

Artemis
Member: Friemler
Solution Friemler Feb 06, 2016, updated at Feb 11, 2016 at 16:39:20 (UTC)
Goto Top
Hallo Artemis,

als ich schrieb "Die Verarbeitung von Text war wohl eher nicht geplant." meinte ich die Designer/Entwickler des Batchscript-Interpreters, nicht Deine Aufgabenstellung.

Dein Text besteht aus Dateipfaden, also spreche ich auch davon. Ich bin da nicht "ins Dateimanagement abgerutscht".

Ich hatte Dir mit Version 2 des Scripts eine Luxusversion gebaut, die Du bequem in der von Dir geschilderten Umgebung (Script liegt in einem Verzeichnis, das in die PATH-Variable eingetragen ist; mit TotalCommander in ein Verzeichnis wechseln, dort eine Konsole öffnen und das Script starten) nutzen konntest. Jetzt hast Du es für den Produktiveinsatz auf das notwendigste eingedampft. Prima.

Das Script ist langsam, weil es für jeden Dateipfad aus Deiner Datei das Unterprogramm ProcessFileName aufrufen muss. Dass ich hierfür ein Unterprogramm verwende liegt daran, dass ich mir den ersten Teil des Dateinamens (vor dem Trennzeichen) der aktuellen Datei für die Verarbeitung der nächsten Datei merken muss (die Zuweisung an die Variable %LastFileName%). Um diese Zuweisung innerhalb der FOR-Schleife im Hauptprogramm zu machen, müsste ich die verzögerte Variablenerweiterung aktivieren (darüber gibt es auch ein Kapitel in meinem Tutorial), was zu Problemen mit Dateipfaden führt, die ein Ausrufezeichen enthalten. Durch die Verwendung des Unterprogramms kann ich auch diese Klippe umschiffen, allerdings auf Kosten der Performance.

So, das war jetzt mein letzter Kommentar zu der Sache - besser geht es nicht, da kannst Du Dich noch zehnmal beschweren. Wenn Du nicht zufrieden bist, versuche eben selbst eine Lösung zu finden. Es gibt außerdem auch noch VBScript. Das ist viel leichter erlernbar als Batchscript, weil es nicht aus einem Sumpf von Design- und Programmierfehlern besteht. Wenn Dir meine Erklärungsversuche zu hoch sind, dann glaube mir wenigstens, dass Deine Wünsche nach mehrstelligen beliebigen Trennzeichen nicht erfüllbar sind. Irgendwelches Optimierungspotenzial gibt es in Deiner eingedampften Scriptversion auch nicht.

Bzgl. "Nachträgliches Bearbeiten von Kommentaren": Rechts neben der Titelzeile jedes Kommentars, neben Datum und Uhrzeit, befindet sich der Link "Bearbeiten". Unter dem Kommentar gibt es rechts ein Menü (dargestellt durch 3 Punkte) neben dem Link für "Kommentieren", dort findest Du auch einen "Bearbeiten"-Link. Beide Links sind natürlich nur sichtbar, wenn Du im Forum eingeloggt bist.

Gruß
Friemler
Member: colinardo
Solution colinardo Feb 06, 2016, updated at Feb 11, 2016 at 16:39:27 (UTC)
Goto Top
Hallo zusammen,
Es gibt außerdem auch noch VBScript. Das ist viel leichter erlernbar als Batchscript, weil es nicht aus einem Sumpf von Design- und Programmierfehlern besteht.
Da muss ich Friemler absolut zustimmen. DOS ist inzwischen in den "mit 50ern" angelangt und es wird so langsam aber sicher Zeit für die Rente face-wink
Deswegen sollte man doch mal öfter mal einen Blick über den Tellerrand wagen und einer moderneren Skriptsprache wie Powershell eine Chance geben, wenn sich mit Ihr das ganze doch mit einem simplen Einzeiler erledigen lässt face-smile.
(gc 'c:\Obstlist.txt') | sort | group {$_.Split('=')} | %{$_.Group} | set-content 'C:\Obstlist.txt'  
Welcher sich selbstverständlich auch mit minimalem Aufwand in eine Batch einbinden ließe:
powershell.exe -ExecutionPolicy ByPass -Command "(gc 'c:\Obstlist.txt') | sort | group {$_.Split('=')} | %%{$_.Group} | set-content 'C:\Obstlist.txt'"  
Grüße Uwe
Member: Artemis
Artemis Feb 07, 2016 at 02:43:24 (UTC)
Goto Top
Hallo Uwe,

vielen Dank für die VB-Scriptzeile, das funktioniert tatsächlich als Batch-Powershell!
Und sogar mehrere Zeichen als Markierer inkl. Leerstellen macht es problemlos.
Allerdings nur mit wenigen Zeichen, und ich kann keine Logik darin erkennen:

Beispiele, habe mit und ohne zusätzliche "Gänsefüßchen" - und auch solche 'Gänsefüßchen' - getestet:

=1= geht
=2= geht
=3= geht
=4= geht nicht ???
=5= geht
ab xy geht
#ß geht, wird aber zu #á
_-_ geht nicht

Gibt es dafür eine Handhabe, Erklärung oder Konfigurationsschema?
Oder/und Deine Empfehlung/Link für meinen Einstieg in VBScript?

Gruß, Artemis
Member: Artemis
Artemis Feb 07, 2016 at 05:28:33 (UTC)
Goto Top
Also,

ich habe jetzt mal beide Skripte im Volleinsatz bei gleichen Bedingungen ("=") gegeneinander antreten lassen, das sind immerhin etwa 30.000 Textzeilen, und die Ergebnisse verglichen.

Tempo:
Skript Friemler ist mit 68 sec etwa 1/3 schneller als Skript Uwe mit 95 sec.

Inhalt:
Skript Friemler hat etwa 20 Textzeilen weniger als Skript Uwe

Aber welche? Und warum?
Dazu habe ich mit einem advanceden Texteditor beide Dateien einem Inhaltsvergleich unterzogen.

Die Ergebnisse sind zunächst einmal chaotisch durchwachsen, weil jedes Skript teils andere (alphabetische) Reihenfolgen (Plätze)der Zeilen erzeugt, was ja aufgrund der wohl unterschiedlichen Routinen logisch und nicht weiter tragisch ist. Aber dadurch ist es natürlich nahezu unmöglich herauszufinden, welche Zeilen denn nun wo zuviel vorhanden sind oder zuwenig.

Der Zufall hat mir aber dann eine verdächtige Stelle gezeigt. Endet ein Dateiname auf *=.* - also z.B. Februar=.jpg, was eine Vorauswahl, jedoch noch keine fertige Bearbeitung mit Varianten bedeutet, dann beläßt es Uwe genauso dabei, während Friemler in diesem Fall das "=" einfach wegmacht: Februar.jpg

Das wäre nun nicht weiter schlimm, wenn es da nicht manchmal noch andere Dateitypen von Februar gäbe, wie Februar.bmp und Februar.tif. Die fallen dann - logischerweise - bei Friemler gleich mit auf den Müll, während Uwe diese unangetastet läßt, genauso wie den routineauslösenden Februar=.jpg selbst.

Uwe sagt: Februar=.jpg gilt nur für jpg´s und sonst nüscht,
während Friemler das eher bayrisch löst: Komm..., weg damit, machts net so a G´schiss!

Im Ergebnis ist es ja egal, da es nur Einzelfälle sind.
Und unter dem Aspekt "Katalogisierung" ist die Friemler´sche Variante da sogar effektiver.

Fazit:

Wenn es bei der einfachen "="-Variante bleibt, schick ich Friemler ins Rennen.
Gibt es aber komplexere Bibliotheken zu katalogisieren, dann kann das nur Uwe übernehmen,
von dem ich evtl. noch ein paar Tricks zu einem erweiterten, logischeren Zeichensatz bekommen.

Artemis
Member: colinardo
Solution colinardo Feb 07, 2016, updated at Feb 11, 2016 at 16:39:49 (UTC)
Goto Top
Zitat von @Artemis:
Allerdings nur mit wenigen Zeichen, und ich kann keine Logik darin erkennen:
Da wird das Encoding deiner Datei wohl nicht erkannt worden sein, das lässt sich im CMDLet Get-Content(gc) zusätzlich als Parameter angeben. Funktioniert hier nämlich problemlos.
Man könnte hier auch Regular-Expressions für die Trennung einsetzen, dann hast du alle Möglichkeiten der Welt face-wink

Grüße Uwe
Member: colinardo
colinardo Feb 07, 2016 updated at 09:10:12 (UTC)
Goto Top
Zitat von @Artemis:

Also,

ich habe jetzt mal beide Skripte im Volleinsatz bei gleichen Bedingungen ("=") gegeneinander antreten lassen, das sind immerhin etwa 30.000 Textzeilen, und die Ergebnisse verglichen.

Tempo:
Skript Friemler ist mit 68 sec etwa 1/3 schneller als Skript Uwe mit 95 sec.
What ? Hier ist das Skript in 5 Sekunden fertig mit 50000 Zeilen generierter Pfade, was hast du für einen museumsreifen Rechner face-smile Btw. lässt sich das bei Bedarf auch noch beschleunigen wenn man möchte.

Inhalt:
Skript Friemler hat etwa 20 Textzeilen weniger als Skript Uwe
??? Da hast du wohl unsere Skripte miteinander verwechselt mein Skript ist ein Einzeiler ...

Aber welche? Und warum?
Don't understand you ....

Der Zufall hat mir aber dann eine verdächtige Stelle gezeigt. Endet ein Dateiname auf *=.* - also z.B. Februar=.jpg, was eine Vorauswahl, jedoch noch keine fertige Bearbeitung mit Varianten bedeutet, dann beläßt es Uwe genauso dabei, während Friemler in diesem Fall das "=" einfach wegmacht: Februar.jpg

Das wäre nun nicht weiter schlimm, wenn es da nicht manchmal noch andere Dateitypen von Februar gäbe, wie Februar.bmp und Februar.tif. Die fallen dann - logischerweise - bei Friemler gleich mit auf den Müll, während Uwe diese unangetastet läßt, genauso wie den routineauslösenden Februar=.jpg selbst.

Uwe sagt: Februar=.jpg gilt nur für jpg´s und sonst nüscht,
während Friemler das eher bayrisch löst: Komm..., weg damit, machts net so a G´schiss!

Im Ergebnis ist es ja egal, da es nur Einzelfälle sind.
Und unter dem Aspekt "Katalogisierung" ist die Friemler´sche Variante da sogar effektiver.

Fazit:

Wenn es bei der einfachen "="-Variante bleibt, schick ich Friemler ins Rennen.
Gibt es aber komplexere Bibliotheken zu katalogisieren, dann kann das nur Uwe übernehmen,
von dem ich evtl. noch ein paar Tricks zu einem erweiterten, logischeren Zeichensatz bekommen.

Wenn man alle deine Bedingungen kennen würde kann man auch auf alle reagieren und abfangen, wenn man sie vorher nicht kennt dann nicht face-wink Mit einem passenden Regex ist das ein Kinderspiel.
Member: Artemis
Artemis Feb 07, 2016 at 22:55:52 (UTC)
Goto Top
Hallo Uwe,

obwohl ich hier als Fachspezifischer Neuling antrete, fühle ich mich teils schnell an den Pranger gestellt, wenn ich meinen Auftrag nicht in spezieller Fachsprache mit hochspezifizierten Parametern stelle. Wenn ich das könnte, dann könnte ich (vermutlich) meine Skripte selber schreiben. Ich bin zwar ein langjährig geübter Batch-Schreiber, auch mit teils sehr kompkexen Konstruktionen, jedoch habe ich nicht die höheren Weihen der FOR-DO-Schleifen mit ihren DELIMs und TOKENs. etc. oder irgendeiner anderen Programmiersprache. Dafür frage ich hier nach Hilfe.

Wenn ich also als "normaler" Windows- und DOS-(Batch)User nach einem Skript frage, das in welcher Form auch immer mit "Text" zu tun hat - und egal ob Text IN einer Datei oder AUßERHALB, alles bei einem Skript ist "Text" - dann gehe ich grundsätzlich als Standard (und als "Unbedarfter ohne höhere Weihen") davon aus, daß jedweder Text sich auf Standard-Text bezieht, den man so tagtäglich in Gebrauch hat. Also Text, der per Tastatur in einem Editor erzeugt werden kann, in allen Dateinamen vorkommen kann, entweder ASCII oder ANSI ist (das kennt man als Normalo), und eben für die landesspezifische Codeseite (hier: 850 Deutschland) an einen typischen Windowsrechner per chcp beauftragt wurde. Das gilt gleichermaßen für Realtext, Kommandos, Parameter, Ziffern und Sonderzeichen. Regular-Expressions? (Zitat colinardo),

Aber vielleicht ist es falsch von mir, wenn ich das grundsätzlich voraussetze - einfach der Einfachheit halber, damit man sich nicht mit unnötigen Diskussionen aufhalten muß. Werde also künftig vorstehenden Passus bei Skriptanfragen gleich mitliefern, damit die Skripte gleich von Anfang an universell DOS-Windows-850-deutscheTastatur-texttauglich geplant werden. Egal in welcher Programmiersprache.

Wenn ich also z.B. "n" Ziffern als Parameter in einer Routine brauche, dann nützt es mir wenig, wenn das beispielsweise nur mit ungeraden Ziffern und außerdem nie mit einer Zahl, die "7" enthält, funktioniert, auch wenn das für die Skriptsprache des jeweiligen Programms der beste Weg wäre. Denn als Fragesteller habe ich selbstverständlich keine Ahnung von dieser speziellen Programmiersprache, die der Programmierer zur Lösung meines Problems ausgewählt hat. Weil normalerweise ist es üblich, "n" Ziffern zu verstehen als "normal" gezählt von 1 bis "unendlich". Erst wenn das nicht geht, werden im 2. Schritt die Einschränkungen definiert. Aber doch nicht umgekehrt, oder?

"Regular-Expressions" für den Parameter im VBSkript klingt gut, ich vermute es ist genau das, wonach ich mich sehne?

...{$_.Split('Meine Oma fährt im Hühnerstall für 4,- $ Motorrad')}...

Das sei der "normale" Standard. Wenn das in diesem Fall aber nicht geht, egal warum, dann bitte extra sagen und/oder den Parameter-Rahmen definieren. Ich halte das für beide Seiten die effektivste Vorgehensweise.

Artemis
Member: Artemis
Artemis Feb 07, 2016 at 23:10:54 (UTC)
Goto Top
Hallo Uwe,

zu Deinem 2. Beitrag: Don't understand you ....

1. Rechner ist schnell - glaub ich zumindest (6-Kern-CPU mit je 3700Mhz, 16 BG Speicher, SSD, W7-Ranking 7,6), jedoch gemessene Zeit = die komplette Routine, in der dieses Skript nur ein Teil ist.

2. Inhalt:
Skript Friemler hat etwa 20 Textzeilen weniger als Skript Uwe
??? Da hast du wohl unsere Skripte miteinander verwechselt mein Skript ist ein Einzeiler ...

Aber welche? Und warum?
Don't understand you ....

Das dürfte nur ein Mißverständnis sein: "20 Textzeilen weniger" bezieht sich nicht auf die Skripte, sondern auf das Zeilenergebnis der zu verarbeitenden Texdateien - nach der Verarbeitung durch eines der Skripte. Denn bei diesen Skripten geht es ja darum, ganz bestimmte Zeilen zu finden und zu löschen. Und weil beide Skripte unterschiedlich sind, kommen offensichtlich unterschiedliche Ergebnisse bei raus.

3. "Wenn man alle deine Bedingungen kennen würde kann man auch auf alle reagieren und abfangen, wenn man sie vorher nicht kennt dann nicht  Mit einem passenden Regex ist das ein Kinderspiel."

Ja, siehe mein vorheriger Absatz zum Thema.
Und bitte sagen, wenn meine Vorstellungen nicht angemessen sind, danke!

Artemis
Member: colinardo
Solution colinardo Feb 08, 2016, updated at Feb 11, 2016 at 16:40:10 (UTC)
Goto Top
obwohl ich hier als Fachspezifischer Neuling antrete, fühle ich mich teils schnell an den Pranger gestell
Hmm, wo ? Ich sehe hier keinerlei provozierenden Aussagen, und Friemler und ich tun ja das mögliche deine mit jedem Post wachsenden Wünsche zu erfüllen, aber das geht eben nur wenn wir alle Bedingungen kennen die du stellst.

Definiere also einfach nochmal ganz klar und knackig alle Bedingungen und Möglichkeiten deiner Namen und wie darauf reagiert werden soll, das geht leider aus obigen Aussagen noch nicht ganz klar hervor.
Dann ändere ich dir den Code entsprechend ab. Dann ist das hier mit zwei weiteren Posts geklärt und es braucht keine 20 weiteren Kommentare für so eine einfache Aufgabe.

Zu überdenken wäre ebenfalls auch mal eure jetzige Ablagestruktur der Files.

Merci.
Member: Artemis
Artemis Feb 08, 2016 at 16:32:44 (UTC)
Goto Top
Du hast recht, das mit dem Pranger ist so nicht richtig, ich habe es wohl eher spiegelbildlich gemeint, weil ich mich zunehmend unwohl gefühlt habe in der Rolle dessen, der irgendetwas und immer mehr fordert, weil ich das gar nicht wollte und auch für unnötig halte. Aber dann unnötig, wenn die Autoren von oben nach unten einschränken würden, aber nicht von unten nach oben: "Vielleicht geht das ja schon, wenn nicht, wird er schon meckern."

Denn ich bin als Unbedarfter natürlich naiv genug, zunächst zu glauben, daß das, was als Parameter im Code innerhalb der "Gänsefüßchen" steht, von mir beliebig abgewandelt oder erweitert werden kann - ohne daß ich von vornherein darauf bestehe. Aber jetzt habe ich dazu gelernt, daß ich mich gleich von vornherein präziser ausdrücken sollte.

ganz klar und knackig, ich versuche es mal:

Die Markierung von Files mit einem Textzeichen sollte ein wenig zukunftssicher sein, also mögliche künftig gewünschte Gestaltzungsvarianten abdecken.

Anfänglich nur

=

ist momentan OK, aber wenn wir uns jetzt schon grad die Arbeit machen, dann sollten wir nächstes Jahr nicht nochmal anfangen müssen, wenn ich dann evtl. 3 Parameter brauche, z.B.

=1=
=2=
=3=
oder
---=---
_-_-_

Es muß nicht der ganze 850-Fundus an Textzeichen und -menge sein, ich bitte nur um einen bescheidenen Parameterrahmen der wenigstens die Ziffern 0-9 enthält, die mit einigen Sonderzeichen kombiniert werden können: # ! = ( ) [ ] { } - . _ ...allesamt erlaubt in NTFS-Dateinamen.

Wenn von diesen Sonderzeichen jedes einzeln viel Arbeit zu programmieren macht, dann reicht mir das "=" kombinierbar mit ein paar Ziffern, wie oben gezeigt, völlig aus.

Wenn es aber einfacher sein sollte, mit nur einer einzigen kleinen Formel gleich mehr (oder gar 850 komplett) auf einen Schlag einzubinden - obwohl ich das gar nie brauchen werde - dann... warum nicht?

Und a Ruh is.
Member: colinardo
Solution colinardo Feb 08, 2016, updated at Feb 11, 2016 at 16:40:25 (UTC)
Goto Top
Darum ging es mir nicht, es ging mir um die Rahmenbedingungen wann welches File als erstes definiert ist, und ob mit oder ohne andere Datei-Extension und ob das Gleichheitszeichen entfernt werden soll wenn es am Ende alleine steht etc.. Wenn man es anhand des Änderungsdatums ermitteln könnte ... das wäre ebenfalls kein Problem. Das Splitten selber ist kein Thema das kann ich dir problemlos so anpassen.

Wenn du nur das obige Skript mit anpassbarem Trennstring brauchst kannst du das hier nehmen:
(gc 'c:\Obstlist.txt') | sort | group {($_ -split [regex]::escape('=2='))} | %{$_.Group} | set-content 'C:\Obstlist.txt'  
Wo dein Trennstring hinkommt solltest du sehen können. Dort kannst du beliebige Zeichenfolgen verwenden, aber bitte immer nur Hochkommas um den String verwenden.
Member: Artemis
Artemis Feb 08, 2016 at 20:25:09 (UTC)
Goto Top
Habe jetzt ein wenig Probleme zu verstehen, was Du alles meinst.
Zunächst verweise ich ganz an den Anfang des Threads, da steht was ich grundsätzlich haben will mit Beispielen.

wann welches File als erstes definiert ist

Von der Erstellung her (dir *.* /A-D /S /OGN /B) sind die ganzen Pfad\Dateiname-Zeilen ja alphabetisch geordnet.
Deshalb ist das erste File mit "=" in seinem Dateinamen, von oben nach unten, bereits vorgegeben, wie auch immer.
Das ist die Sache vom DIR-Befehl, wie er es nun mal macht, und also für das Skript nicht weiter relevant.
Diese 1. gefundene File-Zeile mit "=" soll erhalten bleiben - unverändert -,
alle anderen nachfolgenden (weil ja alphabetisch geordnet), werden gelöscht.

Bzgl. "unverändert": Wenn eine Datei zwar den Markierer "=" hat, jedoch dahinter keine weitere Klassifikation, also so:

C:\Januar\Februar\...\März=.ext
(Das ist eine Datei, die bereits vorausgewählt, aber noch nicht bearbeitet ist, und somit rechts vom "=" noch keine Klassifizierung hat.)

...dann soll dieses "=" samt der ganzen Zeile so wie in diesem Muster erhalten bleiben.
Nachfolgende, gleichnamige Dateien mit diesem Muster *=.* gibt es nie, macht keinen Sinn, es kommen dann immer nur noch Bearbeitungsvarianten, wie:

C:\Januar\Februar\...\März=1a.ext
C:\Januar\Februar\...\März=1b.ext
C:\Januar\Februar\...\März=2a.ext
...

die alle gelöscht werden.
In der Regel beginnt eine solche Datei-Familie aber immer mit beispielsweise

C:\Januar\Februar\...\März=1a.ext
(was dann als 1. Zeile mit "=" genauso erhalten bleibt)

Kommt dann nachfolgen irgendwann beispielsweise

C:\Januar\April\...\März=1a.ext
...

dann beginnt die Bearbeitungroutine von neuem.

ob mit oder ohne andere Datei-Extension
aus den Beispielen ersichtlich: Extension bleibt immer erhalten

ob das Gleichheitszeichen entfernt werden soll wenn es am Ende alleine steht
gerade erklärt: nein.

Wenn man es anhand des Änderungsdatums ermitteln könnte
Versteh ich nicht, tut nichts zur Sache.
Beachte: die DIR-Parameter erzeugen einen einwandfreien Dateipfad, ohne weitere Informationen wie in der DIR-Standardeinstellung, damit eine solche Liste und/oder Teile daraus ggfls. auch ohne weitere Umstände in ein startbares Skript umgewandelt werden kann, z.B. in eine Diashow oder Playliste. Zunächst wird diese Liste in eine Datenbank importiert, und da brauch ich nur funktionale Dateipfade, ohne Datum, Größe und den ganzen Kram.

Das Splitten selber ist kein Thema das kann ich dir problemlos so anpassen.
Dann bitte etwas mehr Variationen und Anzahl Zeichen als nur "=". Siehe meine Beispiele weiter oben.
Idealerweise - wenn ganz einfach realisierbar - alle im Dateipfad von NTFS erlaubten Zeichen, ansonsten eine sinnvolle "handvoll" bzw. die Einschränkungen als Vorgaben definieren.

Schön wäre es außerdem, wenn ich die gesuchte Zeichenkette für diese Routine als Parameter übergeben könnte, so wie den Dateinamen auch, z.B.:

call redundel G:\Datei.txt ---8---

redundel.bat würde dann enthalten:
@echo off
powershell.exe -ExecutionPolicy ByPass -Command "(gc '%1') | sort | group {$_.Split('%2')} | %%{$_.Group} | set-content '%1'"  
goto end

Gruß, Artemis
Member: Artemis
Artemis Feb 09, 2016 at 01:31:42 (UTC)
Goto Top
Hallo Uwe,

danke für das neue Skript, das ja noch vor meinem neuen Beitrag kam.
Leider läuft es nicht, sondern produziert eine Fehlermeldung:
call redu2 G:\HD2.!!!
redu2.bat:
@echo off
powershell.exe -ExecutionPolicy ByPass -Command "(gc '%1') | sort | group {($_ -split [regex]::escape('='))} | %{$_.Group} | set-content '%1'"  
pause
Fehlermeldung:

Der Zeichenfolge, beginnend mit:
Bei Zeile:1 Zeichen:75
"+" (gc 'G:\HD2.!!!') | sort | group {($_ -split [regex]::escape('='))} | 1 <<<< '
fehlt der Terminator: '.
Bei Zeile:1 Zeichen:76
"+" (gc 'G:\HD2.!!!') | sort | group {($_ -split [regex]::escape('='))} | 1' <<<<
+ CategoryInfo : ParserError: (:String) , ParentContainsErrorRecordException
+ FullyQualifiedErrorId : TerminatorExpectedAtEndOfString

(Die beiden "+" am Zeilenanfang hab ich in "+" gesetzt, ansonsten würden sie eine große Schrift erzeugen.)

Artemis
Member: colinardo
Solution colinardo Feb 09, 2016, updated at Feb 11, 2016 at 16:40:38 (UTC)
Goto Top
Du hast ja auch vergessen das Prozentzeichen der Foreach-Schleife zu verdoppeln wenn du die Powershell-Zeile in einer Batch verwendest. Siehe meine ersten Codes oben.
Und da deine Liste wie du schriebst schon sortiert ist kann der überflüssige Sortierschritt ebenfalls entfallen.

powershell -ExecutionPolicy Bypass -Command "(gc '%~1') | group {($_ -split [regex]::escape('%~2'))} | %%{$_.Group} | set-content '%~1'"  
Aufruf redu2.bat "C:\datei.txt" "==2=="
Btw. wenn du die Liste sowieso per Batch aus dem Dateisystem erzeugst, das ließe sich das auch ohne einen zusätzliche Zwischenschritt in eine Textdatei abfackeln und direkt in der Powershell machen, dann entfällt dieser unnötige Zwischenschritt.
powershell -ExecutionPolicy Bypass -Command "gci '%~1' -Recurse | ?{!$_.PSISContainer} | sort Fullname | group {$_.DirectoryName + '\' + ($_.Basename -split [regex]::escape('%~3'))} | %%{$_.Group.Fullname} | set-content '%~2'"  
Aufruf redu2.bat "C:\FolderToScan" "C:\datei.txt" "==2=="

Ansonsten den Beitrag dann bitte noch als gelöst markieren, du hast ja nun Input ein Masse und hast die Wahl. Merci.

Grüße Uwe
Member: Artemis
Artemis Feb 10, 2016 at 03:29:17 (UTC)
Goto Top
Ja richtig, Prozentzeichen aber nicht vergessen (soviel versteh ich von dem Skript nun auch wieder nicht), sondern versehentlich nur die Variante ohne Batch-Umgebung kopiert. Funktioniert jetzt einwandfrei. Dickes Danke!

Dein neuerer Vorschlag "überflüssige Sortierschritt ebenfalls entfallen" läuft dagegen nicht (hab alles genau kopiert und sogar genau Deine Dateinamen übernommen.
Fehlermeldung, gleich 3x, u.a.: "Das angegebene Pfadformat wird nicht unterstützt." ... und es passiert nichts mit der Datei.
Der 2. Parameter "Trennzeichen" reagiert gar nicht. Mir fällt auf, daß die Variablen hier neuerdings alle mit Tilde dazwischen "%~2" gemacht sind, nur als Hinweis.

Den 2. neuen Vorschlag "ohne einen zusätzliche Zwischenschritt in eine Textdatei" - sehr interessant! - hab ich jetzt noch nicht getestet, vielleicht enthält er ja denselben Fehler.

Von mir aus ist die Aufgabe mit VB-Variante Nr.1 gelöst. Aber wenn Du schon diese tollen zusätzlichen Varianten gestrickt hast, willst Du sie evtl. rein ergeizeshalber auch funktionsfähig wissen - ohne auszuschließen, daß erneut ich es verdaddelt habe. Deshalb hier mein nochmaliger Rapport.

Grüße, Artemis
Member: colinardo
Solution colinardo Feb 10, 2016, updated at Feb 11, 2016 at 16:40:42 (UTC)
Goto Top
War nur ein Typo drin (Smartphone sei Dank face-wink), ist korrigiert.

Und zur Info was die Tilde bei den Parametern bewirkt ist, dass bei Parametern eventuelle umschliessende Anführungszichen entfernt werden, solltest du mal einen Pfad mit Leerzeichen verwenden wollen.

Hoffe ich habe ein bisschen die Neugierde für die Powershell geweckt. Aber Achtung, wenn du einmal infiziert bist willst du kein Batch mehr sehen face-smile

So long
Grüße Uwe
Member: Artemis
Artemis Feb 11, 2016 at 05:22:41 (UTC)
Goto Top
Alles paletti.
Aufgabe nicht nur gelöst, auch noch Pauken und Trompeten hinterhergeschoben.
Sauba sag i.
Powershell-Neugier allemal geweckt, werde mir mal den Eingang dazu suchen...

Bis zum nächsten Mal face-monkey

Artemis