lupora
Goto Top

Suchstring Suche aus CSV Datei mit CMD

Hallo zusammen,

ich habe ein Problem und habe 90% der Lösung bereits hier mit der Suche gefunden.
Die letzten 10% fehlen mir noch face-smile

Problem: Ich möchte eine Ordnerstruktur samt Unterordner nach einem exakten Suchstring durchsuchen. Wann immer er eine Datei findet, die auf den Suchstring machted, soll er die Datei in ein Zielverzeichnis kopieren.
Zusatz: Ich möchte den Suchstring nicht nur einmal fix definieren, sondern möchte eine CSV mit Suchstrings bereitstellen. In dieser sind in alle Suchstrings gelistet (immer einer pro Zeile).
Er soll die Suchstrings Zeile für Zeile abarbeiten und jedesmal bei einem Treffer die entsprechende Dateien kopieren. Wenn er die Ordnerstruktur samt Unterordner mit einem String fertig durchsucht hat, holt er sich aus der CSV den nächsten Suchstring.

Das ist mein Script aktuell:

@echo off & setlocal
set "Dateifilter=*MeinSuchString*.pdf"
set "Quelle=C:\RootOrdner"
set "Ziel=C:\Zielordner"
for /f "delims=" %%a in ('dir /s /b /a-d "%Quelle%\%Dateifilter%"') do @(
copy "%%a" "%Ziel%"
)

Wie müsste man meine gewünschte Funktion implementieren? Habe schon rumprobiert aber ohne Erfolg :/

Meine Suchstring CSV Datei sähe so aus:
*MeinSuchString1*.pdf
*MeinSuchString2*.pdf
*MeinSuchString3*.pdf

usw.

Content-ID: 502244

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

Ausgedruckt am: 25.11.2024 um 18:11 Uhr

erikro
erikro 08.10.2019 um 16:56:14 Uhr
Goto Top
Moin,

warum einfach, wenn es auch kompliziert geht. face-wink Auf der Powershell ist das ein Einzeiler:

get-content C:\woauchimmer\suchstrings.txt | %{get-childitem $_ | Copy-Item -Destination c:\zielordner}

Das im Quellordner ausführen und gut ist.

Zitat von @Lupora:
Meine Suchstring CSV Datei sähe so aus:
*MeinSuchString1*.pdf
*MeinSuchString2*.pdf
*MeinSuchString3*.pdf

BTW: Das ist keine CSV, sondern eine einfache Textdatei. Eine CSV hat Spaltenüberschriften und Trennzeichen zwischen den Überschriften und den einzelnen Attributen eines Datensatzes.

hth

Erik
Friemler
Friemler 08.10.2019 um 18:18:55 Uhr
Goto Top
Hallo @Lupora,

falls es eine Batch-Lösung sein muss, wickele noch eine Schleife drumherum:

@echo off & setlocal

set "SuchStrings=C:\SuchStrings.txt"  
set "Quelle=C:\RootOrdner"  
set "Ziel=C:\Zielordner"  

for /f "usebackq delims=" %%a in ("%SuchStrings%") do (  
  for /f "delims=" %%b in ('dir /s /b /a:-d "%Quelle%\%%~a" 2^>NUL') do (  
    copy "%%~b" "%Ziel%"  
  )
)

Siehe auch mein Tutorial zur FOR-Schleife.

Grüße
Friemler
141320
141320 08.10.2019 aktualisiert um 19:03:15 Uhr
Goto Top
Zitat von @erikro:
> get-content C:\woauchimmer\suchstrings.txt | %{get-childitem $_ | Copy-Item -Destination c:\zielordner}
> 

Eine Alternative zu der Variante etwas abgewandelt dann ist die Suche mit Get-ChildItem nur ein Aufruf.
Get-ChildItem 'C:\Rootordner\*' -Include (gc 'D:\suchstrings.txt') -File | copy-item -Destination 'C:\zielordner'  

Auch in der Batch nutzbar wenn's sein muss
@echo off
powershell -EP Bypass -NoP -C "Get-ChildItem 'C:\Rootordner\*' -Include (gc 'D:\suchstrings.txt') -File | copy-item -Destination 'C:\zielordner'"  
Lupora
Lupora 08.10.2019 um 21:23:31 Uhr
Goto Top
Hallo zusammen,

erstmal danke für all eure Antworten. Ihr seid ja voll die Profis face-smile

Tatsächlich sollte es eine Batch Datei sein.

@Friemler
Enthält dein Code bereits die Liste die hinterlegt werden muss?
Suche in deinem Code die Stelle wo er die Textdatei einliest?

@erikro
Du hast also den Powershell Aufruf direkt in die Batch integriert?

Könnte man noch einen Befehl dazu packen, damit er alle gefundenen Bilder (die auf Suchstrings matchen) nicht in einen gemeinsamen Zielordner verschiebt? Sondern das er jeweils einen Ordner angelegt wird mit dem Namen des Suchstrings? Falls Ordner schon vorhanden, kopiert er die gefundenen Dateien da rein. Falls nicht, wird der Ordner erstellt?
141320
141320 08.10.2019 aktualisiert um 21:56:17 Uhr
Goto Top
Zitat von @Lupora:


Könnte man noch einen Befehl dazu packen, damit er alle gefundenen Bilder (die auf Suchstrings matchen) nicht in einen gemeinsamen Zielordner verschiebt? Sondern das er jeweils einen Ordner angelegt wird mit dem Namen des Suchstrings? Falls Ordner schon vorhanden, kopiert er die gefundenen Dateien da rein. Falls nicht, wird der Ordner erstellt?
Kann man, aber dann muss man auch die Sonderzeichen wie das Sternchen usw. durch entsprechend gültige Zeichen ersetzen, denn sonst lässt sich ein Ordner mit so einem Suchstring erst gar nicht anlegen!

gc 'D:\suchstrings.txt' | ?{$_ -notmatch '^\s*$'} | %{  
    $dest = "c:\zielordner\$($_ -replace '[<>:"/\\|\?\*]','_')"  
   if(!(Test-Path $dest)){md $dest -force | out-null}
    gci "c:\Rootordner\$_" -File | copy-item -Destination $dest  
}
Lupora
Lupora 10.10.2019 um 09:18:41 Uhr
Goto Top
Herzlichen Dank hierfür! Das ist voll nett von dir!

Noch eine Detailfrage: Das Script erstellt in jedem Falle einen Unterordner. Auch wenn es zu dem Suchstring keine Dateien gefunden hat.
Kann man es so abändern, dass es nur einen Ordner erstellt, wenn es tatsächlich auch eine Datei gefunden hat die auf den String matched?

Und letzte Frage:
Kann ich in der Textdatei auch mit dem Wildcard * beliebige Suchstrings zusammen setzen?

z.b.

*Bilder*Oktober*Mon

Er würde dann einen Ordnererstellen der heißt evtl. "Bilder_Oktober_Mon" und dort drin wären Bilder die z.b. heißen
"Fest_Bilder_32434_Oktober_Montag.jpg

Geht das ? face-smile
141320
141320 10.10.2019 aktualisiert um 15:10:19 Uhr
Goto Top
Klar
gc 'D:\suchstrings.txt' | ?{$_ -notmatch '^\s*$'} | %{  
    $files = gci "c:\Rootordner\$_" -File -recurse  
    if ($files){
         $dest = "c:\zielordner\$($_ -replace '[<>:"/\\|\?\*]','_')"  
         if(!(Test-Path $dest)){md $dest -force | out-null}
         $files | copy-item -Destination $dest -Force -verbose
    }
}
Lupora
Lupora 10.10.2019 um 15:03:57 Uhr
Goto Top
irgendwas ist seltsam. Durchsucht die Powershell auch alle Unterordner? Im Zweifel ist der Rootordner ein Ordner mit vielen unterordnern in denen jeweils Bilddateien liegen.

Das Programm scheint nicht zu starten face-sad
141320
141320 10.10.2019 aktualisiert um 15:12:41 Uhr
Goto Top
Zitat von @Lupora:

irgendwas ist seltsam. Durchsucht die Powershell auch alle Unterordner?
Nein diese Anforderung hast du nicht erwähnt, dafür musst du im Get-Childitem Befehl den Parameter -recurse setzen. Hab ich dir oben ergänzt.
Das Programm scheint nicht zu starten face-sad
Hier geht's einwandfrei. Du machst also was falsch.
Lupora
Lupora 10.10.2019 um 15:24:34 Uhr
Goto Top
Also das Script wird ausgeführt. Meine Suchstring Datei sieht so aus:

*Bilder*
*Registerdaten*Januar

Die Wildcards habe ich selber gesetzt. Sind die falsch? Ich will das er bei *Bilder* alles findet, wo dieser Substring drin sind.

Ist das falsch?
Lupora
Lupora 10.10.2019 um 15:44:09 Uhr
Goto Top
Ok, habe es nochmal überprüft. Wenn ich die Sternchen in der Suchstring.txt weglasse, funktioniert es. Kann ich denn mehrere Suchstrings kombinieren?

Also z.B.

Bilder*Oktober*2019

Dann würde er einen Ordner erstellen "Bilder_Oktober_2019" und darin wären folgende Bilder:

Bilder_Canon_Oktober_324234_sdfsdf_2019_TopShot1.jpg
Bilder_Canon_Oktober_324234_sdfsdf_2019_TopShot2.jpg
Bilder_Canon_Oktober_324234_sdfsdf_2019_TopShot3.jpg

geht so etwas ? face-smile
141320
Lösung 141320 10.10.2019 aktualisiert um 17:05:06 Uhr
Goto Top
Die Wildcards habe ich selber gesetzt. Sind die falsch?
Jepp falsch
Bilder*Oktober*2019
Müsste lauten *Bilder*Oktober*2019*, da ja bei deinen Beispielen am Ende noch andere Strings kommen face-wink.
*Bilder*
Das ist korrekt und funktioniert auch!

Solltest du mal lesen
Supported Wildcards for the Windows File System

Tschö.

Erst mal lesen bevor du nur im dunklen stocherst
Lupora
Lupora 11.10.2019 um 07:40:54 Uhr
Goto Top
Danke für den Hinweis!

Jetzt noch letzte zwei Fragen: Das Script braucht teilweise sehr lange, da ich wirklich gigantische Ordner Mengen habe (> 5k Ordner).
Frage hierzu: Kann ich in der Powershell ein ECHO ausgeben wie bei CMD? Damit ich sehe wo er gerade steht. Ich starte das SCript und 60 Minuten passiert nichts :/ Ich weiß dann nicht, ob er sich aufgehängt hat oder gerade wo hängt. Kann ich die Ausgabe irgendwie sehen?

Zweite Frage: Kann man das Script auch umbauen (für einen anderen Anwendungsfall): Dass er alle Ordnerstrukturen durchsucht und immer wenn er einen Ordner findet, der auf den Suchstring matched, wird dieser komplett kopiert? Also das er nicht alle Dateien durchsucht. Sondern sucht "Ah, da gibts einen Ordner dessen Name auf meinen Suchstring matched, den kopiere ich in Zielordner" ?
TomTomBon
TomTomBon 11.10.2019 um 10:48:10 Uhr
Goto Top
Moin Moin,

PS unterstützt alle CMD aspekte, auch "echo" face-smile

Es gibt natürlich bessere aspekte, inkl. archivierung in eine csv.
Nur da müßte man wirklich gut sein in PS um das aus dem Ärmel zu schütteln, bin ich nicht,
oder das gesamte Skript sehen und einen Ansatz kriegen.

Auch dann muss Ich es mit viel Arbeit analysieren..

So long
Tom
erikro
erikro 11.10.2019 um 12:49:50 Uhr
Goto Top
Moin,

Zitat von @Lupora:
Jetzt noch letzte zwei Fragen: Das Script braucht teilweise sehr lange, da ich wirklich gigantische Ordner Mengen habe (> 5k Ordner).
Frage hierzu: Kann ich in der Powershell ein ECHO ausgeben wie bei CMD? Damit ich sehe wo er gerade steht. Ich starte das SCript und 60 Minuten passiert nichts :/ Ich weiß dann nicht, ob er sich aufgehängt hat oder gerade wo hängt. Kann ich die Ausgabe irgendwie sehen?

Dafür gibt es die schöne Funktion write-progress.
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell. ...

hth

Erik
Friemler
Lösung Friemler 11.10.2019 aktualisiert um 15:55:07 Uhr
Goto Top
Hallo Lupora,

Ich starte das Script und 60 Minuten passiert nichts

Aufgrund dessen könnte es sinnvoll sein, eine alternative Lösung in Batchscript zu testen. Ich habe in dem Code unten bereits Deinen Zusatzwunsch nach dem Anlegen eines Verzeichnisses, das so benannt ist wie die Suchmaske, integriert. Wenn keine Dateien kopiert wurden, wird das Verzeichnis wieder gelöscht.

@echo off & setlocal

:: -----------------------------------------------------------------------------
:: Benutzerkonfiguration
:: -----------------------------------------------------------------------------
set "SuchStrings=C:\SuchStrings.txt"  
set "Quelle=C:\RootOrdner"  
set "Ziel=C:\Zielordner"  
:: -----------------------------------------------------------------------------


:: -----------------------------------------------------------------------------
:: Hauptscript
:: -----------------------------------------------------------------------------
set "VBScript=%TEMP%\ReplaceWildcards.vbs"  

call :WriteVBScript

for /f "usebackq delims=" %%a in ("%SuchStrings%") do (  
  call :ProcessSearchTerm "%%~a"  
)

del "%VBScript%" 2>NUL  

exit /b 0



:: -----------------------------------------------------------------------------
:: Unterprogramme
:: -----------------------------------------------------------------------------
:ProcessSearchTerm
  set "SearchTerm=%~1"  
  set "DirName="  

  for /f "delims=" %%z in ('cscript /nologo "%VBScript%" "%~1"') do (  
    set "DirName=%%~z"  
  )

  if "%DirName%" equ "" exit /b 0  

  md "%Ziel%\%DirName%" 2>NUL  
  set /a FilesCopied=0
  
  for /f "delims=" %%z in ('dir /s /b /a:-d "%Quelle%\%SearchTerm%" 2^>NUL') do (  
    copy "%%~z" "%Ziel%\%DirName%"  
    set /a FilesCopied=1
  )
  
  if %FilesCopied% equ 0 (
    rd "%Ziel%\%DirName%" 2>NUL  
  )
exit /b 0


:WriteVBScript
  > "%VBScript%" echo strInput  = WScript.Arguments(0)  
  >>"%VBScript%" echo strOutput = Replace(strInput, "*", "_")  
  >>"%VBScript%" echo strOutput = Replace(strOutput, "?", "_")  
  >>"%VBScript%" echo WScript.Echo strOutput  
exit /b 0

Im Abschnitt Benutzerkonfiguration musst Du die Pfade zu Deinen Verzeichnissen und (in Zeile 6) den Pfad zu der Datei mit den Suchstrings eintragen.

Das sollte dann auch Deine Frage von oben beantworten:

Enthält dein Code bereits die Liste die hinterlegt werden muss?
Suche in deinem Code die Stelle wo er die Textdatei einliest?

Die Datei wird im Kopf der FOR-Schleife in Zeile 19 eingelesen (in meinem alten Script von weiter oben war es Zeile 7).

Grüße
Friemler
Lupora
Lupora 14.10.2019 um 20:53:21 Uhr
Goto Top
Hallo Friemler,

erstmal WOW !!!! Du hast dir ja mega Mühe gegeben. Herzlichen Dank für deine tolle Arbeit!

Das Skript funktioniert toll. Ich hätte noch einen Verbesserungsvorschlag:

Das Script erzeugt ja Ordner, entsprechend dem Suchstring.
Am Anfang und ENde des Ordnernamens setzt er immer einen Unterstrich. Kann man das noch entfernen?

Die Ordner wo die Bilder drin liegen, sehen immer so aus:

_Oktober_
_BilderausdemUrlaubXY_
Friemler
Friemler 14.10.2019 um 21:15:26 Uhr
Goto Top
Hallo @Lupora,

die _-Zeichen werden dort eingesetzt, wo Dein Suchbegriff Wildcard-Zeichen (also * oder ?) enthält, da diese Zeichen für Verzeichnis- bzw. Dateinamen verboten sind.

Aber OK, wenn Du eine Ausnahme für führende und angehängte _-Zeichen haben möchtest, ersetze das Unterprogramm WriteVBScript durch folgenden Code:

:WriteVBScript
  > "%VBScript%" echo strInput  = WScript.Arguments(0)  
  >>"%VBScript%" echo strOutput = Replace(strInput, "*", "_")  
  >>"%VBScript%" echo strOutput = Replace(strOutput, "?", "_")  
  >>"%VBScript%" echo(  
  >>"%VBScript%" echo If Left(strOutput, 1)  = "_" Then strOutput = Mid(strOutput, 2)  
  >>"%VBScript%" echo If Right(strOutput, 1) = "_" Then strOutput = Mid(strOutput, 1, Len(strOutput) - 1)  
  >>"%VBScript%" echo(  
  >>"%VBScript%" echo WScript.Echo strOutput  
exit /b 0


Was mich noch interessieren würde: Wie lange benötigt mein Batchscript im Vergleich zur PowerShell-Lösung? Um vergleichbare Ergebnisse zu erhalten müsstest Du allerdings zuerst den Befehl

dir /s /b /a:-d "Pfad-des-Quellverzeichnisses\*.*"

in einem CMD.exe-Fenster ausführen. Dadurch füllt der NTFS-Dateisystemtreiber seinen Cache mit den Daten der zu verarbeitenden Verzeichnisstruktur und sowohl mein Batchscript als auch das PowerShell-Script starten mit den gleichen Voraussetzungen.

Grüße
Friemler