.bat/.cmd Datei zum Verschieben von Dateien unter Voraussetzungen

Langsam wirds unübersichtlich. :D
Code:
$path = "c:\users\admin\desktop\test"
$list = gci -path $path | ? {$_.extension -eq ".txt"}
$max = 104857600 # 100MB
     
$sum = ($list | measure-object -property length -sum).sum # Summe der Dateigrößen
$runs = 0
     
while ($sum -gt $max){
    $count = 1 # Zähler
    while (($list |select -first $count | measure-object length -sum).sum -lt $max){ # zählt benötigte Dateien für Dateigröße $max
         $count++
    }
    $runs++
    $splitline = ((($list | select -first 1).name) -split "_") #Splite bis zu "_"
    $folder = "\" + $splitline[0] + "{0:D3}" -f $runs +"\"

    new-item ($path + $folder) -type directory
    $list |select -first $count | move -destination ($path + $folder)
    
    # lese Ordner neu ein
    $list = gci -path $path | ? {$_.extension -eq ".txt"}
    $sum = ($list | measure-object -property length -sum).sum
     
}
if(!($sum -gt $max)){
    # verschiebt restliche Dateien
    if($runs -gt 0 -and ($list | measure-object).count -ne 0){ # wenn $list nicht leer
         $list | move -destination ($path + $folder)
    }
    echo "zu wenig Dateien / Skript beendet"
}
 
Zuletzt bearbeitet:
Für meine Bedürfnisse wahrscheinlich zu kompliziert..
Er gibt mir beim Ausführen einen Fehler an, dass etwas mit der Zeile
$splitline = ((($list | select -first 1).name) -split "_") #Splite bis zu "_"


nicht stimmt. Der Fehler popt leider nur bruchteile einer Sekunde auf.
Es steht etwas von "nach - muss ein Wert angegeben werden".
Dachte, dieser Fehler tritt auf, da der Wert "_" zwei mal in der Dateibenennung vorkommt. Habe diesen Parameter jedoch auf "_01" geändert (Das Segment "_01" ist in jeder Datei, einzigartig enthalten)

Die Funktion der Dateibenennung ist jedoch rein kosmetisch.

Es bleibt aber leider noch das Problem bestehen, dass das derzeitige script
entweder die letzten .txt Dateien offen liegen lässt, bzw. der letzte Ordner zu groß verpackt wird.

if(!($sum -gt $max)){
# verschiebt restliche Dateien
if($runs -gt 0 -and ($list | measure-object).count -ne 0){ # wenn $list nicht leer
$list | move -destination ($path + $folder)

Gibt es hierfür eine Lösung? Bzw. wo steckt hier der Fehler?
 
Bei der Bennenung steh ich grad auf dem Schlauch, bei mir funktioniert das problemlos - egal wie viele "_" enthalten sind. Sieht dann so aus:

"Datei_a_xy.txt", "Datei_b_xy.txt", ...

landen dann in 100MB Paket in Ordner die folgendermaßen heißen:

Datei001
Datei002

wobei ich unten noch den Unterstrich hinzugefügt hab. Wenn du das ganze im "Bearbeiten" Editor ausführst kannst du hochscrollen und dir den genauen Fehler anschauen. Außerdem gibts rudimentäre Debug-Funktionen.


Zu der Sache mit den offenen Dateien:
Ich hatte dich so verstanden, dass die übrigen Dateien zum letzten Ordner "dazugeschlagen" werden sollen. Habs jetzt mal so abgeändert, dass für diese ein neuer Ordner angelegt wird - der dann natürlich kleiner als 100MB ist.

Code:
$path = "c:\xyz\test"
$list = gci -path $path | ? {$_.extension -eq ".txt"}
$max = 104857600 # 100MB

$sum = ($list |  measure-object -property length -sum).sum # Summe der Dateigrößen
$runs = 0 

while ($sum -gt $max){
    $count = 1 # Zähler
    while (($list |select -first $count | measure-object length -sum).sum -lt $max){ # zählt benötigte Dateien für Dateigröße $max
         $count++
    }
    $runs++
    $splitline = ((($list | select -first 1).name) -split "_") #Splite bis zu "_"
    $folder = "\" + $splitline[0] +"_" + "{0:D3}" -f $runs +"\"

    new-item ($path + $folder) -type directory
    $list |select -first $count | move -destination ($path + $folder)
    
    # lese Ordner neu ein
    $list = gci -path $path | ? {$_.extension -eq ".txt"}
    $sum = ($list | measure-object -property length -sum).sum
     
}
if(!($sum -gt $max)){
    # verschiebt restliche Dateien
    if($runs -gt 0 -and ($list | measure-object).count -ne 0){ # wenn $list nicht leer
         $folder = "\" + $splitline[0] +"_" + "{0:D3}" -f ($runs + 1) +"\"
         new-item ($path + $folder) -type directory
         $list | move -destination ($path + $folder)
    }
    echo "zu wenig Dateien / Skript beendet"
}
 
Zuletzt bearbeitet:
Zu der Sache mit den offenen Dateien:
Ich hatte dich so verstanden, dass die übrigen Dateien zum letzten Ordner "dazugeschlagen" werden sollen. Habs jetzt mal so abgeändert, dass für diese ein neuer Ordner angelegt wird - der dann natürlich kleiner als 100MB ist.
Genau danach hab ich gesucht! Super, danke!

Schaue mir die Benennung auch gleich nochmal an..
Ergänzung ()

Funktioniert jetzt einwandfrei!

Vielen Dank und großes Lob dafür!
 
Hier ein kleines Update:

Habe leider vergessen anzumerken, dass die Dateien nicht zufällig, sondern der Benennung nach aufsteigend verpackt werden sollen.

Die Dateien sind also alle fortlaufend benannt und sollen dementsprechend auch in die erstellten Ordner verschoben werden.

Datei_0001.txt - Datei_0200.txt -->[verschieben nach Verzeichnis bis 100MB erreicht ] Datei001
Datei_0201.txt - Datei_0400.txt -->[verschieben nach Verzeichnis bis 100MB erreicht ] Datei002
Datei_0401.txt - Datei_0800.txt -->[verschieben nach Verzeichnis bis 100MB erreicht ] Datei003

(wobei ich hier davon ausgehe, dass die jeweiligen ranges 0001-0200 etc. jeweils 100MB entsprechen)
Nach jetzigem Skript geschieht diese Aufteilung willkürlich.
Lässt sich diese Funktion leicht integrieren? Habt ihr einen Tipp?
 
Eigentlich sollte das automatisch in der gewünschten Reihenfolge geschehen. Du kannst mal versuchen bei $list noch ein
Code:
 | sort -property name
anzuhängen.

Wie lauten denn die genauen Namen (zum testen)?
 
Sieht aus, als ob es so funktioniert.

Code:
 new-item ($path + $folder) -type directory
    $list |[COLOR="Red"][SIZE="4"][B][COLOR="Red"] [SIZE="6"]sort name[/SIZE][/COLOR][/B][/SIZE][/COLOR] | select -first $count | move -destination ($path + $folder)
    # lese Ordner neu ein
    $list = gci -path $path | ? {$_.extension -eq ".txt"}
Ergänzung ()

Interessant wäre noch eine Funktion, die die Unterteilung der Dateien nicht bloß nach

"verschiebe in Verzeichnisse max 100MB"

vollzieht, sondern

"splitte in gleich große Packete zu max 100MB"


Müsste dazu das ganze Skript neu aufgerollt werden?
Könnte mir vorstellen, dass es sich anhand einer vorhergehenden Abfrage der gesamten Dateimenge nach dem Schema

"ermittle gesamte Dateimenge im Quellverzeichnis -> definiere als "Σ" ;
checke, wieviele Verzeichnisse(x) nötig sind damit
{Σ / x} < 100 MB



Habe keine Möglichkeit gefunden, es hier zu integrieren.

Code:
    $path = "C:\path"
    $list = gci -path $path | ? {$_.extension -eq ".txt"}
    $max = 104857600 # 100MB
     
    $sum = ($list | measure-object -property length -sum).sum # Summe der Dateigrößen
    $runs = 0
     
    while ($sum -gt $max){
    $count = 1 # Zähler
    while (($list |select -first $count | measure-object length -sum).sum -lt $max){ # zählt benötigte Dateien für Dateigröße $max
    $count++
    }
    $runs++
    $splitline = ((($list | select -first 1 ).name) -split "_") #Splite bis zu "_"
    $folder = "\" + $splitline[0] +"_" + "{0:D2}" -f $runs +"\" # Anzahl der Stellen beim Erstellen der Verzeichniserweiterung "_01 usw."
     
    new-item ($path + $folder) -type directory
    $list | sort name | select -first $count | move -destination ($path + $folder)
    # lese Ordner neu ein
    $list = gci -path $path | ? {$_.extension -eq ".txt"}
    $sum = ($list | measure-object -property length -sum).sum
    }
    if(!($sum -gt $max)){
    # verschiebt restliche Dateien
    if($runs -gt 0 -and ($list | measure-object).count -ne 0){ # wenn $list nicht leer
    $folder = "\" + $splitline[0] +"_" + "{0:D2}" -f ($runs + 1) +"\" # packe die übrigen Dateien in neues Verzeichnis
    new-item ($path + $folder) -type directory
    $list | move -destination ($path + $folder)
    }
    echo "Dateien fertig verpackt - Skript beendet"
    }
 
Du wirst es ohne größeren Aufwand nicht hinbekommen, exakt gleich große Ordner zu generieren.
Nimm als Beispiel deine Dateisumme ergibt eine Primzahl - was dann?
 
Da hast du sicher recht.

Habe mir jedoch noch eine andere Möglichkeit vorgestellt.
Explezit geht es mir hier um die Extremwerte bei dem letzten, erstellten Verzeichnis.

Habe versucht hier bei der letzten Abfrage eine if-Bedingung einzufügen.
Leider wirft das Skript beim Versuch diese Abfrage duchzuführen (also erst beim Erstellen des letzten Verzeichnisses) eine Fehlermeldung aus.

Code:
    $path = "C:\path" # Quellverzeichnis
    $list = gci -path $path | ? {$_.extension -eq ".txt"}
    $max = 36700160 # 35MB  # Maximale Verzeichnisgröße
    $min = 10485760 # 10MB  # Maximale Dateigröße um die Dateien dem letzten Ordner hinzu zu fügen
        
    $sum = ($list | measure-object -property length -sum).sum # Summe der Dateigrößen
    $runs = 0
     
    while ($sum -gt $max)
    {
        $count = 1 # Zähler
        while (($list | select -first $count | measure-object length -sum).sum -lt $max){ # zählt benötigte Dateien für Dateigröße $max
        $count++
    }
    
    # Definition der neuen Verzeichnisse
    $runs++
    $splitline = ((($list | select -first 1 ).name) -split "_") # Splite bis zu "_"
    $folder = "\" + $splitline[0] +"_" + "{0:D2}" -f $runs +"\" # Anzahl der Stellen beim Serializen
     
    new-item ($path + $folder) -type directory
    $list | sort name | select -first $count | move -destination ($path + $folder)
    # lese Ordner neu ein
    $list = gci -path $path | ? {$_.extension -eq ".txt"}
    $sum = ($list | measure-object -property length -sum).sum
    }
    if(!($sum -gt $max)){
    # verschiebt restliche Dateien
    if($runs -gt 0 -and ($list | measure-object).count -ne 0){ # wenn $list nicht leer
    
        then ($list | measure-object length -sum).sum -lt $min
        $folder = "\" + $splitline[0] +"_" + "{0:D2}" -f ($runs) +"\"
        $list | sort name | select -first $count | move -destination ($path + $folder)
        
        else
        $folder = "\" + $splitline[0] +"_" + "{0:D2}" -f ($runs + 1) +"\"
        new-item ($path + $folder) -type directory
        $list | move -destination ($path + $folder)
    }
    echo "Dateien fertig verpackt - Skript beendet"
    }

Es sollte hier am Ende eine Abfragen durchgeführt werden,
ob die restlichen Dateien <= 10MB sind; wenn ja
schiebe in das letzte erstellte Verzeichnis (das bereits mit max 35MB gefüllt ist); sonst wenn >10MB -> erstelle nächstes, neues, eigenes Verzeichnis.


Error:

Die Benennung "then" wurde nicht als Name eines Cmdlet, einer Funktion, einer Skriptdatei oder eines ausführbaren Programms erkannt. Überprüfen Sie die Schreibweise des Namens, oder o
b der Pfad korrekt ist (sofern enthalten), und wiederholen Sie den Vorgang.
Bei C:\dir\powerShellSkriptMod5LastFolderThing.ps1:31 Zeichen:13
+ then <<<< ($list | measure-object length -sum).sum -lt $min
+ CategoryInfo : ObjectNotFound: (then:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException

Die Benennung "else" wurde nicht als Name eines Cmdlet, einer Funktion, einer Skriptdatei oder eines ausführbaren Programms erkannt. Überprüfen Sie die Schreibweise des Namens, oder o
b der Pfad korrekt ist (sofern enthalten), und wiederholen Sie den Vorgang.
Bei C:\dir\powerShellSkriptMod5LastFolderThing.ps1:35 Zeichen:13
+ else <<<<
+ CategoryInfo : ObjectNotFound: (else:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException


Da scheine ich ja großen Mist gebaut zu haben.
 
Eigentlich recht eindeutige Fehler. ;)
Kanns grad nicht checken, aber so sollts laufen:


Code:
  if(!($sum -gt $max)){
    # verschiebt restliche Dateien
    if($runs -gt 0 -and ($list | measure-object).count -ne 0){ # wenn $list nicht leer
        if(($list | measure-object -property length -sum).sum -lt 10485760){ #kleiner 10MB > kein neuer Ordner
            $folder = "\" + $splitline[0] +"_" + "{0:D3}" -f ($runs) +"\"
            $list | move -destination ($path + $folder)
        }
        else{
            $folder = "\" + $splitline[0] +"_" + "{0:D3}" -f ($runs + 1) +"\"
            new-item ($path + $folder) -type directory
            $list | move -destination ($path + $folder)
        }  
    }
    echo "Dateien fertig verpackt - Skript beendet"
}
 
Zuletzt bearbeitet:

Code:
Fehlender Anweisungsblock nach "if ( Bedingung )".
Bei C:\dir\powerShellSkriptMod5LastFolderThingMod.ps1:31 Zeichen:9
+          <<<< $folder = "\" + $splitline[0] +"_" + "{0:D2}" -f ($runs) +"\"
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : MissingStatementBlock
 
Sollt jetzt gehen.

Bei der Benennung von den Ordnern muss man ein bisschen aufpassen, gab jetzt verschiedenen Versionen hier im Thread. $folder sollte halt überall das gleiche Format haben...
 

Ähnliche Themen

Zurück
Oben