Créer unique nom de fichier de commandes Windows
J'ai vu de nombreux posts sur la création d'un nom de fichier unique à partir de la naïveté %TEMPS% à l'plausible (mais insuffisante) %RANDOM%. À l'aide de wmic os get localdatetime
est beaucoup mieux, mais il peut encore échouer sur plusieurs CPU/core machines. Le script suivant va finalement échouer lorsque vous exécutez en 5+ coques sur un multiple de base de la machine.
@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /L %%i IN (0, 1, 1000) DO (
FOR /F "usebackq" %%x IN (`wmic os get localdatetime ^| find "."`) do (set MYDATE=%%x)
ECHO MYDATE is now !MYDATE!
IF EXIST testuniq_!MYDATE!.txt (
ECHO FAILED ON !MYDATE!
GOTO TheEnd
)
COPY NUL >testuniq_!MYDATE!.txt
)
:TheEnd
EXIT /B 0
Quelqu'un aurait-il un moyen fiable pour créer un nom de fichier unique dans un script shell?
- Ce n'est pas souvent nous poser une question au lot-fichier les terres que les bons de souscription de plus de 5 réponses. +1 question intéressante!
Vous devez vous connecter pour publier un commentaire.
Tout système qui s'appuie sur un nombre aléatoire peut théoriquement échouer, même à l'aide d'un GUID. Mais le monde semble avoir accepté que les Guid sont assez bonnes. J'ai vu du code posté quelque part qui utilise CSCRIPT JScript pour générer un GUID.
Il y a d'autres façons:
D'abord, je vais supposer que vous êtes en train de créer un fichier temporaire unique. Depuis le fichier sera supprimé une fois que votre processus se termine, tout ce que vous devez faire est d'établir un verrou exclusif sur une ressource dont le nom est un dérivé de votre temp de nom de fichier. (en réalité, j'en sens inverse - le temp le nom est dérivé de la ressource verrouillée nom).
Redirection établit un verrou exclusif sur le fichier de sortie, j'ai donc tout simplement dériver un nom dans le temps (avec de 0.01 seconde preciscion), et de tenter de verrouiller un fichier avec ce nom dans le dossier temp de l'utilisateur. Si cela échoue que je boucle en arrière et essayer à nouveau jusqu'à ce que je réussisse. Une fois que j'ai du succès, je suis assurée d'avoir la propriété exclusive de ce verrouillage, et tous les produits dérivés (à moins que quelqu'un intentionnellement rompt le système).
Une fois mon processus se termine, le verrou sera libéré, et un fichier temporaire avec le même nom peut être réutilisé plus tard. Mais le script normalement supprime les fichiers temporaires lors de la résiliation.
Boucle en raison de la collision de nom doit être rare, sauf si vous êtes vraiment insister sur votre système. Si oui, vous pouvez réduire le risque de boucle par un facteur de 10 si vous utilisez
WMIC OS GET LOCALDATETIME
au lieu de%TIME%
.Si vous êtes à la recherche pour un unique et persistante de nom, alors le problème est un peu plus difficile, puisque vous ne pouvez pas maintenir le verrou indéfiniment. Pour ce cas, je vous recommande le WMIC OS LocalDateTime approche, couplé avec deux chèques pour les collisions de noms.
La première case permet simplement de vérifier que le fichier n'existe pas déjà. Mais c'est une condition de concurrence - deux processus pourraient faire le chèque en même temps. La deuxième case crée le fichier (vide) et établit un temporaire verrou exclusif sur elle. L'astuce est de s'assurer que le verrou est maintenu pour une période de temps plus longue que celle qu'il prend pour un autre processus pour vérifier si le fichier existe. Je suis paresseux, j'ai donc tout simplement utiliser DÉLAI d'établir une 1 seconde d'attente de façon plus que nécessaire.
L' :getUniqueFile routine attend trois arguments - un nom de base, une extension, et le nom de la variable où le résultat doit être stocké. Le nom de base peut inclure le lecteur et le chemin d'accès de l'information. Toutes les informations de chemin d'accès doit être valide, sinon la routine va entrer dans une boucle infinie. Ce problème pourrait être résolu.
Le dessus doit être garantie pour renvoyer un nouveau nom de fichier unique pour le chemin d'accès donné. Il y a beaucoup de place pour l'optimisation d'établir une commande à exécuter lors de la serrure vérifier que prend "assez longtemps", mais pas "trop long"
set "lockFile=%lockFile: =%
9>
et8>
moyens. Désolé de vous déranger, mais peut-être que vous pouvez me pointer dans la bonne direction? Merci 🙂%TEMP%
ne doivent pas contenir d'espaces ou d'autres caractères posant problème. Donc le temp de nom de fichier chemin d'accès doit être correctement cité partout où il est utilisé.Le Lot-JScript hybride script ci-dessous utilise WSH l'ofs.GetTempName() méthode qui a été conçu justement à cet effet:
GetTempName()
générer un nom unique ou pas, parce supplémentairesFileExists(fileName)
test de garantir que le fichier est unique.GetTempName()
est juste une méthode plus simple à utiliser que la combinaison de hasard et de l'heure.Vous pouvez utiliser
certutil
base64 encode%date% %time%
avec un%random%
graines comme ceci:Dans le cas où le même scénario est en cours d'exécution à partir du même répertoire par plusieurs utilisateurs, j'ai ajouté
%username%
pour les fichiers temp pour éviter de nouveaux conflits. Je suppose que vous pourriez remplacer%random%
avec%username%
pour le même effet. Alors vous feriez seulement obtenir un conflit si un seul utilisateur exécute le même bloc de code deux fois en même temps.(Edit: ajouté
%username%
comme une semence pour l'unicité.)%username%
comme une graine. Ou si vous voulez augmenter le caractère aléatoire de%random%
, puisset /a "rand = (%random% + 1) * (%random% + 1) * %random%"
devrait résulter en un nombre entier aléatoire dans la pleine signé de 32 bits gamme de -2147483648 à 2147483647. (Parce que quand un certain nombre dépasse 32 bits, le cmd interprète roule pour les nombres négatifs.) Vrai qu'il y a un peu de pondération et cela ne se traduira pas par des dérivés de nombres premiers, mais vous êtes toujours obtenir plus de hasard, tout de même.Voici un coupe-bas version de mon fichier temporaire générateur de créer un fichier nommé
tempnn.nnn
dans le%temp%
répertoire.Une fois
tempnn.nnn
a été créé, il est simple de créer comme beaucoup d'autres tempfiles que vous voulez pour le processus en ajoutant un suffixe à%y$$%
, par exemple,%y$$%.a
etc. Bien sûr, cela suppose que certains autres processus n'est pas au hasard créer des noms de fichiers sans l'aide de cette procédure.if exist
et une boucle.J'aime Aacini du JScript solution hybride. Tant que nous sommes des emprunts à d'autres environnements d'exécution, comment au sujet de l'aide .NET Système.GUID avec PowerShell?
Il y A longtemps dans un galax..groupe de discussion appelé alt.ms-dos.lot, un intervenant a insisté sur le dépôt d'un QBASIC solution à chaque problème posé, enveloppé dans un lot coque et prétendant qu'il s'agit du lot, car elle n'est utilisée standard de Microsoft-logiciel fourni.
Après un long moment, il a été guéri de ses égarements, mais j'ai été gravement allergique aux méthodes hybrides depuis. Assurez-vous - si elle guérit le problème, blah,blah - et parfois, il est impossible d'échapper à ce cours (exécuter le lot silencieusement, par exemple). En dehors de cela, je ne veux vraiment pas thebother de l'apprentissage d'une nouvelle langue ou deux...c'est pour ça que je évitent *script de solutions. YMMV.
Soi - voici une autre approche...
Essentiellement, définir le titre pour quelque chose d'aléatoire. Notez que
x%random%x
est utilisé, et non pas simplement%random%
de sorte qu'une recherche de "x123x" ne les détecte pas "x1234x".Ensuite, obtenir une verbose tasklist, l'emplacement de la ligne d'en souligner l'intitulé et le titre. La première ligne retournée par
findstr
sera le souligner, la prochaine sera mistargetline
et de toutes les autres retours indiquent que le titre n'est pas unique, afin de revenir, de le modifier et essayez à nouveau jusqu'à ce qu'elle est unique.Enfin, obtenir l'ID de processus qui est dans la deuxième colonne, en notant que la première est inconnue largeur (donc pourquoi le soulignement est saisi.)
Résultat : ce processus de PID qui doit être unique et peut donc être utilisé comme base pour un unique fichier temporaire nom - construire dans un répertoire réservé pour la fin.
Je voudrais vous présenter une autre méthode et de savoir s'il y a des trous de est-il. S'il vous plaît laissez-moi savoir. Merci.
Ou, pour l'exécuter, sans créer un .ps1 fichier:
Afin de vérifier que la bonne tâche est trouvé, le titre est définie à une rare valeur et tasklist.exe est utilisé pour la recherche de la valeur retournée par getppid.ps1.
rendre le contenu du fichier d'un objet, utilisez le pointeur de la memaddress que la première partie de votre nom de fichier et un Rand() comme votre deuxième partie. l'adresse de la mémoire sera unique pour tous les objets, même avec plusieurs instances en cours d'exécution.