luninator
Goto Top

BATCH-Datei zur zufälligen Auswahl von Dateien

Hallo zusammen,

vorweg - ich bin kein richtiger Programmierer. Als Jugendlicher - zu DOS-Zeiten - habe ich mit BATCH-Dateien kleine Rollenspiele gebastelt, ich dachte immer ich kann das ein bisschen - aber anscheinend ist dem nicht wirklich so ;)

Ich möchte gerne aus einer großen Menge an Dateien eine bestimmte Anzahl zufällig auswählen und in ein anderes Verzeichnis kopieren. Hintergrund für die Praktiker: Es handelt sich dabei um JPG-Dateien von handgeschriebenen Protokollen, die zufällig und anonymisiert kontrolliert werden sollen. Die Anonymisierung habe ich derzeit über einen Batch-Vorgang in IrfanView gelöst. Die Auswahl der JPG-Dateien ist aktuell noch mein Problem. Für die Thematik "zufällige Auswahl von Dateien" hab ich eine Menge Lösungsvorschläge finden können, leider haben die alle nicht funktioniert - denn jetzt kommt die Schwierigkeit meines Problems:

- Die Ursprungsdaten liegen in Unterverzeichnissen, innerhalb dieser Unterverzeichnisse sind die Dateien nach dem gleichen System benannt - die Dateinamen können also mehrfach auftreten
- zu jedem Protokoll gibt es immer drei JPGs (fiktiver Dateiname): XYZ001.jpg, XYZ001_a.jpg und XYZ001_b.jpg - ich benötige immer nur die XYZ001.jpg ohne dem _a oder _b
- Mit den bisherigen Lösungsansätzen konnte ich nicht mehr nachvollziehen, aus welchem Unterordner die Dateien kopiert wurden. Ebenso hatte ich ein Problem bei doppelten Dateinamen und natürlich hatte ich auch viele JPGs mit dem _a oder _b hinten dran.

Jetzt habe ich gelesen, ich kann per Batch auch eine Art Logfile erstellen lassen, da bin ich aber garnicht richtig weitergekommen. Theoretisch würde es aber auch vollkommen ausreichen wenn die Datei so umbenannt wird, dass der Unterordner rückverfolgbar ist. Letzteres darf nur nicht offensichtlich sein. Also die Dateien aus Unterordner "01" müsste sich z.B. in XYZ001_ABC.jpg, XYZ002_ABC.jpg, usw... umbenennen. Also immer ein ABC bei Unterordner 01, ein KWM bie 02, usw... Dann ist ja nur durch das Wissen dieser Umbenennung eine Rückverfolgung möglich. Bei letzterer Idee wäre auch das Problem mit den doppelten Dateinamen vom Tisch, aber hier tappe ich dann völlig in der Planlosigkeit herum, wie das umzusetzen ist.

Ich bin für jede Hilfe dankbar. Wenn mein Problem zu komplex ist, um in einem Forum dazu Hilfestellung zu geben, sagt das ruhig ;)
Ggf. kennt auch jemand ein fertiges Tool, was diese Anforderungen gerecht wird.

Grüße aus München

Content-Key: 666378

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

Ausgedruckt am: 29.03.2024 um 14:03 Uhr

Mitglied: 148121
148121 04.05.2021 aktualisiert um 12:32:59 Uhr
Goto Top
Machs doch gleich mit Powershell

Nach deinem Schema:
# quellordner 
$quelle = 'D:\quelle'  
# Zielordner (hier werden die Dateien hin kopiert
$ziel = 'D:\ziel'  
# Anzahl der auszuwählenden Dateien
$randomcount = 2
# Zuordnung zu Ordnernamen definieren
$map = @{
    '01' = 'ABC'  
    '02' = 'KWM'  
}
# ab geht's ... 
ls $quelle -File -Filter *.jpg -Recurse | ?{$_.Basename -notmatch '_[ab]$'} | get-random -Count $randomcount | copy-item -Destination {(join-path $ziel "$($_.BaseName)_$($map[$_.Directory.Name])$($_.Extension)")} -verbose  
Alternative dazu ohne fest hinterlegtes Schema sondern mit Logdatei in der die Dateinamens Zuordnung abgelegt wird und Ticks als Randomizer im Dateinamen.
# quellordner 
$quelle = 'D:\quelle'  
# Zielordner (hier werden die Dateien hin kopiert
$ziel = 'D:\ziel'  
# Logdatei in der die Zuordnung der Quelle zur Zieldatei notiert wird
$log = 'D:\copylog.csv'  
# Anzahl der auszuwählenden Dateien
$randomcount = 2
# ab geht's ... 
ls $quelle -File -Filter *.jpg -Recurse -PipelineVariable file | ?{$_.Basename -notmatch '_[ab]$'} | get-random -Count $randomcount | %{  
    copy-item $_.FullName -Destination (join-path $ziel "$($_.BaseName)_$([datetime]::Now.Ticks)$($_.Extension)") -PassThru | select @{n='Source';e={$file.Fullname}},@{n='Target';e={$_.Fullname}} | Export-CSV $log -Delimiter ";" -NoType -Encoding UTF8 -Append  
}
Gruß w.
Mitglied: HansDampf06
HansDampf06 04.05.2021 um 13:46:37 Uhr
Goto Top
Warum darf denn die Rückverfolgbarkeit des Unterordners nicht offensichtlich sein? Sind denn die Unterordner bzw. ihre Zuordnung offensichtlich?

Für denjenigen, z.B. für Dich, der das Mapping 01 -> ABC, 02 -> ... in Deinem Script fest verdrahtet, ist natürlich die Zuordnung offensichtlich, weil er das Mapping schlichtweg kennt. Dem könntest Du nur begegnen, wenn das Mapping selbst mit zufälligen Zuweisungen agiert. Dann müsste das Mapping natürlich irgendwo dokumentiert werden, wenn zu einem späteren Zeitpunkt eine Rückverfolgung (manuell oder automatisch) erfolgen soll.

Wann ist denn eine Rückverfolgung überhaupt erforderlich? Welches Ziel soll mittels einer Rückverfolgung erreicht werden?

Viele Grüße
HansDampf06
Mitglied: Luninator
Luninator 27.05.2021 um 10:45:31 Uhr
Goto Top
sorry für die verspätete Rückmeldung. Ich war auf Dienstreise und hab das ein wenig aus den Augen verloren...

@148121: Vielen Dank schonmal für deine Ansätze. Hat mich einiges an Zeit gekostet mich da durchzugoogeln um das selbst zu verstehen - bzw um zu verstehen, dass Powershell dann weit ausserhalb meines eigenen Aktionsspielraumes liegt ;)
Ich hab aber einen Kollegen gefunden, der sich da ein bisschen auskennt und gehe mit ihm gemeinsam da mal dran

@hansdampf: Es geht um handgeschriebene Protokolle, die inhaltlich (nach einem Schema) kontrolliert werden sollen. Die Prokolle können von unterschiedlichen Arbeitsplätzen kommen, jeder dieser Arbeitsplätze legt die Protokolle als JPG in einem Ordner ab, bzw. dies geschieht automatisch (digitaler Stift). Das Problem dabei: Innerhalb der Ordner, haben die Protokolle die gleichen Dateibezeichnungen. Der "Kontrolleur" soll aber nicht erkennen, von welchem Arbeitsplatz das Protokoll stammt. Die Rückverfolgung ist dann später sehr wichtig, um eine Aussage treffen zu können, wo gut und wo nicht so gut dokumentiert wird.
Mitglied: Luninator
Luninator 13.07.2021 um 10:11:52 Uhr
Goto Top
ich war beruflich arg im Stress und musste mein kleines Projekt etwas zurückstellen. Ich habe mich nun mit PowerShell ISE mal ein wenig angefreundet und konnte dank euch auch erste Erfolge verzeichnen. Wirklich nochmal dickes Danke an euch!

@148121: Dein zweiter Code macht ziemlich genau das, was ich brauche. Super! Ich hab soweit alles angepasst, dass es zum Testen bereits gut läuft. Ich hab mir mühsam ergoogelt wie ich alle Unterordner mit einbeziehen kann um dann festzustellen, dass der Befehl schon mit drin war ;) Aber nur so lernt man selbst dazu...

Aktuell hab ich nur ein Problem in der Logfile. Dort wird bei allen kopierten Dateien der identische Ursprung angegeben (letzte Datei im letzten Unterordner). Leider werde ich aus dem Codeschnipsel für die Log-Datei nicht schlau um da einen eigenen Ansatz zu finden.

Ebenso wäre es noch klasse, wenn nicht insgesamt X Dateien zufällig ausgewählt werden würden, sondern pro Unterordner. Ich hab das versucht mit der Angabe der einzelnen Unterordner bei der Quelle zu lösen (und -Recurse entfernt):
$quelle = 'D:\quelle1';'D:\quelle2';'D:\quelle3'  
aber wie ihr alle vermutlich wisst, führt das nicht dazu, dass dann aus jeder Quelle die gewünschte Anzahl kopiert wird, sondern wieder nur aus allen zusammen. Bei dieser Variante wurde im Übrigen in der Logfile immer die letzte Datei aus dem ersten Quellordner als Ursprung angegeben.

Wenn ihr mir nochmal helfen könntet, wäre das klasse. Mit meinem amateurhaften Programmierkenntnissen stecke ich da jetzt fest. Aber immerhin hab ich zumindest Teile des Codes durch meine Recherche verstanden. Vielen dank schonmal dafür ;)
Mitglied: Luninator
Luninator 13.07.2021 um 16:25:54 Uhr
Goto Top
Ich hab mich jetzt nochmal hingesetzt und den Großteil aller Befehle/Variablen gegoogelt um den Code besser zu verstehen.

Eine Lösung habe ich letztendlich hinbekommen - vermutlich schmunzelt ihr Profis dabei:

ich hab jeden Unterordner als eigene Quelle definiert:
$quelle1 = 'D:\quelle1'  
$quelle2 = 'D:\quelle2'  
$quelle3 = 'D:\quelle3'  
usw...

und dann natürlich den unteren Teil für jede Quelle einmal kopiert:
ls $quelle1 -File -Filter *.jpg -Recurse -PipelineVariable file | ?{$_.Basename -notmatch '_[ab]$'} | get-random -Count $randomcount | %{  
    copy-item $_.FullName -Destination (join-path $ziel "$($_.BaseName)_$([datetime]::Now.Ticks)$($_.Extension)") -PassThru | select @{n='Source';e={$file.Fullname}},@{n='Target';e={$_.Fullname}} | Export-CSV $log -Delimiter ";" -NoType -Encoding UTF8 -Append  
}
ls $quelle2 -File -Filter *.jpg -Recurse -PipelineVariable file | ?{$_.Basename -notmatch '_[ab]$'} | get-random -Count $randomcount | %{  
    copy-item $_.FullName -Destination (join-path $ziel "$($_.BaseName)_$([datetime]::Now.Ticks)$($_.Extension)") -PassThru | select @{n='Source';e={$file.Fullname}},@{n='Target';e={$_.Fullname}} | Export-CSV $log -Delimiter ";" -NoType -Encoding UTF8 -Append  
}
usw...

damit wird aus jedem Unterordner die gewünschte Menge herausgefischt. Die Logfile ist immer noch fehlerhaft und zeigt als Quelldatei immer die letzte Datei aus dem letzten Quellordner an - aber da es diesmal pro Auswahl nur ein Quellordner ist, stimmt zumindest der Ordner in der Logfile und das reicht mir bereits!

Der Fehler in der Log-Datei ist nun nur noch ein Schönheitsfehler. Der Code wurde jetzt länger (stört mich nicht), aber sollte mal ein Ordner hinzukommen, dann muss man natürlich den Code manuell anpassen. Gibt es da nicht doch vielleicht eine einfachere Lösung?
Mitglied: 148656
148656 13.07.2021 um 17:19:34 Uhr
Goto Top
Moin,

Du musst nicht Stundenlang im Netz suchen.
Das Forum hat alles, was du brauchst.
Powershell Leitfaden für Anfänger

Für deine multiplen Quellen, schau dir den Link über Arrays an.

Gruß
C.C.
Mitglied: Luninator
Luninator 14.07.2021 um 11:01:13 Uhr
Goto Top
danke, das hatte ich auch schon gefunden, aber stellenweise schaffe ich den Transfer in den Code nicht.

Die Quellordner gebe ich jetzt einfach alle einzeln an, das hat auch positive Nebeneffekte für mich. Jetzt muss ich nur an der Dateiauswahl noch ein bisschen feilen.

Einerseits werden mir noch falsche Dateien ausgewählt:
?{$_.Basename -notmatch '_[ab]$'}  
nach meinem Verständnis werden damit Dateien mit Unterstrich und zwei folgenden Zeichen am Ende des Dateinamens ausgeschlossen. Ich habe aber mehr und unterschiedliche viele Zeichen hinten dran. Besser wäre für mich ein Kriterium "nur Dateien mit einem Dateinamen von genau 10 Zeichen" oder alternativ auch einer Dateigröße über 900kb. Beides ist mir nicht gelungen...l Mein Ansatz für die Dateigröße war dies mit "-SizeRange 900kb" zu lösen, hat aber nicht geklappt:
ls $quelle01 -File -Filter *.jpg -SizeRange 900kb -Recurse -PipelineVariable file | ?{$_.Basename -notmatch '_[ab]$'} | get-random -Count $randomcount | %{  
    copy-item $_.FullName -Destination (join-path $ziel "$($_.BaseName)_$([datetime]::Now.Ticks)$($_.Extension)") -PassThru | select @{n='Source';e={$file.Fullname}},@{n='Target';e={$_.Fullname}} | Export-CSV $log -Delimiter ";" -NoType -Encoding UTF8 -Append  
}
hab ich das SizeRange einfach nur an der falschen Stelle? Hab auch versucht statt dem "ab" bei -notmatch die korrekten Endungen einzufügen, aber das hat auch nicht geholfen.

Ebenso wollte ich mir noch einbauen, dass nur Dateien mit einem Datum der letzten 30 Tage in die Auswahl kommen. Da war mein Ansatz:
-LastWriteTimeRange 0,((get-date) -(new-timespan -days 30))
aber auch hier hab ich die korrekte Stelle im Code nicht gefunden...
Mitglied: Luninator
Luninator 26.07.2021 aktualisiert um 13:27:22 Uhr
Goto Top
oh Mann, ich werd einfach aus dem Code nach dem # ab geht's ... nicht schlau ;)

Ich hab jetzt die Bedingung der Dateiendung mal herausgenommen und durch eine Datumseingrenzung ersetzt:

ls $quelle -File -Filter *.jpg -Recurse -PipelineVariable file | ?{!$_.PsIsContainer -and $_.LastWriteTime -cge (Get-Date).AddDays(-30)} | get-random -Count $randomcount | %{
    copy-item $_.FullName -Destination (join-path $ziel "$($_.BaseName)_$([datetime]::Now.Ticks)$($_.Extension)") -PassThru | select @{n='Source';e={$file.Fullname}},@{n='Target';e={$_.Fullname}} | Export-CSV $log -Delimiter ";" -NoType -Encoding UTF8 -Append  
}

jetzt bekomme ich nur noch Dateien jünger als 30 Tage. Soweit so gut!

Nur "Dateigröße über 900kb" als Auswahlkriterium hab ich noch nicht geschafft... Bin schon am verzweifeln...