Erstellen Sie einen eindeutigen Dateinamen Windows-Batch

8

Ich habe viele Posts über das Erstellen eines eindeutigen Dateinamens von der naiven% TIME% bis zur plausiblen (aber nicht ausreichenden)% RANDOM% gesehen. Die Verwendung von wmic os get localdatetime ist viel besser, aber es kann immer noch auf mehreren CPU / Core-Maschinen fehlschlagen. Das folgende Skript wird schließlich fehlschlagen, wenn es in 5+ Shells auf einem Multiple-Core-Rechner ausgeführt wird.

%Vor%

Hat jemand eine zuverlässige Möglichkeit, einen eindeutigen Dateinamen in einem Shell-Skript zu erstellen?

    
lit 06.01.2015, 16:00
quelle

8 Antworten

10

Jedes System, das auf einer Zufallszahl beruht, kann theoretisch fehlschlagen, selbst wenn es eine GUID verwendet. Aber die Welt scheint akzeptiert zu haben, dass GUIDs gut genug sind. Ich habe irgendwo Code gesehen, der CSCRIPT JScript verwendet, um eine GUID zu generieren.

Es gibt andere Möglichkeiten:

Zuerst werde ich davon ausgehen, dass Sie versuchen, eine einzigartige temporäre Datei zu erstellen. Da die Datei gelöscht wird, sobald Ihr Prozess beendet ist, müssen Sie lediglich eine exklusive Sperre für eine Ressource einrichten, deren Name eine Ableitung Ihres temporären Dateinamens ist. (Tatsächlich gehe ich in umgekehrter Richtung - der temporäre Name wird vom Namen der gesperrten Ressource abgeleitet).

Die Umleitung erstellt eine exklusive Sperre für die Ausgabedatei, daher leite ich einfach einen Namen aus der Zeit (mit 0,01 Sekunden Präzisierung) ab und versuche, eine Datei mit diesem Namen im temporären Ordner des Benutzers zu sperren. Wenn das fehlschlägt, gehe ich zurück und versuche es erneut, bis es mir gelingt. Sobald ich Erfolg habe, bin ich garantiert alleiniger Besitzer dieser Sperre und aller Ableitungen (es sei denn, jemand setzt das System absichtlich außer Kraft).

Sobald mein Prozess beendet ist, wird die Sperre aufgehoben und eine temporäre Datei mit demselben Namen kann später wiederverwendet werden. Normalerweise löscht das Skript die temporäre Datei jedoch nach Beendigung.

%Vor%

Schleifen aufgrund von Namenskollisionen sollten selten sein, es sei denn, Sie beanspruchen Ihr System wirklich. Wenn dies der Fall ist, können Sie die Wahrscheinlichkeit einer Schleife um den Faktor 10 verringern, wenn Sie WMIC OS GET LOCALDATETIME anstelle von %TIME% verwenden.

Wenn Sie nach einem persistenten eindeutigen Namen suchen, ist das Problem etwas schwieriger, da Sie die Sperre nicht unbegrenzt aufrecht erhalten können. Für diesen Fall empfehle ich den Ansatz von WMIC OS LocalDateTime, gekoppelt mit zwei Überprüfungen auf Namenskollision.

Die erste Überprüfung überprüft einfach, dass die Datei noch nicht existiert. Aber das ist eine Race Condition - zwei Prozesse könnten gleichzeitig den Check machen. Die zweite Überprüfung erstellt die Datei (leer) und richtet eine temporäre exklusive Sperre für sie ein. Der Trick besteht darin, sicherzustellen, dass die Sperre für einen Zeitraum aufrechterhalten wird, der länger ist als für einen anderen Prozess, um zu prüfen, ob die Datei existiert. Ich bin faul, also benutze ich TIMEOUT, um eine Wartezeit von einer Sekunde aufzubauen - viel mehr als nötig.

Die Routine: getUniqueFile erwartet drei Argumente - einen Basisnamen, eine Erweiterung und den Variablennamen, in dem das Ergebnis gespeichert werden soll. Der Basisname kann Laufwerks- und Pfadinformationen enthalten. Alle Pfadinformationen müssen gültig sein, andernfalls wird die Routine in eine Endlosschleife eintreten. Dieses Problem könnte behoben werden.

%Vor%

Das oben genannte sollte garantiert einen neuen eindeutigen Dateinamen für den gegebenen Pfad zurückgeben. Es gibt viel Platz für die Optimierung, um einen Befehl zum Ausführen während der Sperrprüfung einzurichten, die "lang genug", aber nicht "zu lang" dauert

    
dbenham 06.01.2015, 21:12
quelle
4

Das nachfolgende Batch-JScript-Hybridskript verwendet die WSHO-Methode fso.GetTempName (), die genau für diesen Zweck entwickelt wurde:

%Vor%     
Aacini 06.01.2015 18:18
quelle
4

Sie könnten certutil verwenden, um Base64 für %date% %time% mit einem %random% samen wie folgt zu codieren:

%Vor%

Wenn dasselbe Skript von mehreren Benutzern aus demselben Verzeichnis ausgeführt wird, habe ich den temporären Dateien %username% hinzugefügt, um weitere Konflikte zu vermeiden. Ich nehme an, Sie könnten %random% durch %username% für denselben Effekt ersetzen. Dann würden Sie nur einen Konflikt bekommen, wenn ein einzelner Benutzer denselben Codeblock zweimal gleichzeitig ausführt.

(Bearbeiten: %username% als Startwert für die Eindeutigkeit hinzugefügt.)

    
rojo 06.01.2015 16:03
quelle
3
%Vor%

Hier ist eine abgespeckte Version meines temporären Generators, um eine Datei namens tempnn.nnn im Verzeichnis %temp% zu erstellen.

Sobald tempnn.nnn erstellt wurde, können Sie einfach so viele weitere temporäre Dateien erstellen, wie Sie möchten, indem Sie ein Suffix an %y$$% anhängen, zB %y$$%.a usw. Das setzt natürlich einen anderen Prozess voraus erstellt nicht zufällig Dateinamen, ohne diese Prozedur zu verwenden.

    
Magoo 06.01.2015 16:18
quelle
1

Ich mag Aacinis JScript-Hybrid-Lösung. Solange wir uns von anderen Laufzeitumgebungen ausleihen, sollten Sie wissen, wie Sie .NET verwenden können. System.GUID mit PowerShell?

%Vor%     
rojo 06.01.2015 21:16
quelle
1

Vor langer Zeit bestand in einer galax..newsgroup namens alt.msdos.batch ein Mitarbeiter darauf, für jedes Problem eine QBASIC-Lösung zu veröffentlichen, die in eine Batch-Shell eingepackt war und behauptete, sie sei stapelweise, da sie nur Standard-Microsoft- mitgelieferte Software.

Nach einer langen Zeit wurde er von seinen verirrten Wegen geheilt, aber seitdem bin ich allergisch gegen hybride Methoden. Sicher - wenn es das Problem heilt, blah, blah - und manchmal gibt es kein Entkommen auf diesem Kurs (z. B. lautlos laufen). Abgesehen davon möchte ich wirklich nicht, dass sie eine oder zwei neue Sprachen lernen ... Also Deshalb scheue ich * Skript-Lösungen. YMMV.

Also - hier ist ein anderer Ansatz ...

%Vor%

Stellen Sie den Titel im Wesentlichen auf etwas Zufälliges ein. Beachten Sie, dass x%random%x verwendet wird, nicht einfach %random% , so dass eine Suche nach "x123x" "x1234x" nicht erkennt.

Als nächstes rufen Sie eine ausführliche Aufgabenliste auf, indem Sie die Zeile suchen, die die Überschrift und den Titel unterstreicht. Die erste Zeile, die von findstr zurückgegeben wird, ist die Unterstreichung, die nächste setzt targetline und jede weitere Rückkehr zeigt an, dass der Titel nicht eindeutig ist. Also gehe zurück, ändere es und versuche es erneut, bis es eindeutig ist.

Abschließend, holen Sie sich die Prozess-ID, die in der zweiten Spalte ist, und beachten Sie, dass die erste unbekannte Breite hat (daher warum die Unterstreichung erfasst wird).

Ergebnis: Die PID dieses Prozesses muss eindeutig sein und kann daher als Grundlage für einen eindeutigen Namen für die temporäre Datei verwendet werden - erstellen Sie sie in einem für diesen Zweck reservierten Verzeichnis.

    
Magoo 09.01.2015 19:12
quelle
1

Ich würde gerne eine andere Methode einreichen und herausfinden, ob es irgendwelche Löcher gibt. Lass es mich wissen, bitte. Danke.

%Vor%

Oder um es auszuführen, ohne eine .ps1-Datei zu erstellen:

%Vor%

Um zu überprüfen, ob die richtige Aufgabe gefunden wurde, wird der Titel auf einen unwahrscheinlichen Wert gesetzt und tasklist.exe wird verwendet, um nach dem von getppid.ps1 zurückgegebenen Wert zu suchen.

%Vor%     
lit 09.05.2015 17:56
quelle
0

Machen Sie den Dateiinhalt zu einem Objekt, verwenden Sie die Zeiger-Memadresse als ersten Teil Ihres Dateinamens und einen Rand () als zweiten Teil. Die Speicheradresse ist für alle Objekte eindeutig, auch wenn mehrere Instanzen ausgeführt werden.

    
Bryan Devaney 06.01.2015 16:10
quelle

Tags und Links