Ces règles ont été découvertes après des tests approfondis sur une machine Vista. Aucun test n'a été effectué avec l'unicode dans les noms de fichiers._
RENAME nécessite 2 paramètres - un masque source, suivi d'un masque cible. Le masque source et le masque cible peuvent tous deux contenir les caractères génériques *
et/ou ?
. Le comportement des jokers change légèrement entre les masques source et cible.
Note - REN peut être utilisé pour renommer un dossier, mais les jokers ne sont pas autorisés dans le masque source ou le masque cible lors du renommage d'un dossier. Si le SourceMask correspond à au moins un fichier, le(s) fichier(s) sera(ont) renommé(s) et les dossiers seront ignorés. Si le masque source correspond uniquement à des dossiers et non à des fichiers, une erreur de syntaxe est générée si des caractères génériques apparaissent dans la source ou la cible. Si le masque source ne correspond à rien, alors une erreur “fichier non trouvé” se produit.
De plus, lors du renommage des fichiers, les jokers ne sont autorisés que dans la partie nom de fichier du masque source. Les jokers ne sont pas autorisés dans le chemin menant au nom du fichier.
sourceMask
Le sourceMask fonctionne comme un filtre pour déterminer quels fichiers sont renommés. Les jokers fonctionnent ici de la même manière qu'avec toute autre commande qui filtre les noms de fichiers.
?
- correspond à n'importe quel 0 ou 1 caractère excepté .
Ce joker est gourmand - il consomme toujours le caractère suivant s'il ne s'agit pas d'un .
Cependant, il ne correspondra à rien sans échec si à la fin du nom ou si le caractère suivant est un .
*
- correspond à n'importe quel 0 ou plusieurs caractères y compris .
(avec une exception ci-dessous). Ce joker n'est pas gourmand. Il correspondra à autant ou moins que nécessaire pour permettre aux caractères suivants de correspondre.
Tous les caractères non wildcard doivent se correspondre, à quelques exceptions près.
.
- Se correspond ou peut correspondre à la fin du nom (rien) s'il ne reste plus de caractères. (Note - un nom Windows valide ne peut pas se terminer par .
)
{space}
- Se correspond ou peut correspondre à la fin du nom (rien) s'il ne reste plus de caractères. (Note - un nom Windows valide ne peut pas se terminer par {space}
)
*.
à la fin - correspond à 0 ou plusieurs caractères excepté .
Le .
qui se termine peut en fait être n'importe quelle combinaison de .
et {space}
tant que le tout dernier caractère du masque est .
C'est la seule et unique exception où *
ne correspond pas simplement à un ensemble de caractères.
Les règles ci-dessus ne sont pas si complexes. Mais il y a une autre règle très importante qui rend la situation confuse : Le masque source est comparé à la fois au nom long et au nom court 8.3 (s'il existe). Cette dernière règle peut rendre l'interprétation des résultats très délicate, car elle n'est pas toujours évidente lorsque le masque est comparé au nom court.
Il est possible d'utiliser RegEdit pour désactiver la génération de noms courts 8.3 sur les volumes NTFS, ce qui rend l'interprétation des résultats du masque de fichier beaucoup plus simple. Tous les noms courts qui ont été générés avant la désactivation des noms courts seront conservés.
targetMask
Note - Je n'ai pas fait de tests rigoureux, mais il semble que ces mêmes règles fonctionnent également pour le nom cible de la commande COPY
Le targetMask spécifie le nouveau nom. Il est toujours appliqué au nom long complet ; Le targetMask n'est jamais appliqué au nom court 8.3, même si le sourceMask correspond au nom court 8.3.
La présence ou l'absence de jokers dans le masque source n'a pas d'incidence sur la façon dont les jokers sont traités dans le masque cible.
Dans la discussion qui suit, c
représente tout caractère qui n'est pas *
, ?
, ou .
Le targetMask est traité par rapport au nom source strictement de gauche à droite sans aucun retour en arrière.
c
- Avance la position dans le nom source uniquement si le caractère source n'est pas .
, et ajoute toujours c
au nom cible. (Remplace le caractère qui était dans la source par c
, mais ne remplace jamais .
)
?
- Fait correspondre le caractère suivant du nom long de la source et l'ajoute au nom cible tant que le caractère source n'est pas .
Si le caractère suivant est .
ou si à la fin du nom source, aucun caractère n'est ajouté au résultat et la position actuelle dans le nom source est inchangée.
*
à la fin du masque cible - Ajoute tous les caractères restants de la source à la cible. S'il est déjà à la fin de la source, il ne fait rien.
*c
- Correspond à tous les caractères de la position actuelle jusqu'à la dernière occurrence de c
(correspondance gourmande sensible à la casse) et ajoute l'ensemble des caractères correspondants au nom de la cible. Si c
n'est pas trouvé, alors tous les caractères restants de la source sont ajoutés, suivis de c
C'est la seule situation que je connaisse où la correspondance de fichiers Windows est sensible à la casse.
*.
- Correspond à tous les caractères source de la position actuelle jusqu'à la dernière occurrence de .
(correspondance gourmande) et ajoute l'ensemble de caractères correspondant de caractères au nom de la cible. Si .
n'est pas trouvé, alors tous les caractères restants de la source sont ajoutés, suivis de .
*?
- Ajoute tous les caractères restants de la source à la cible. Si la source se trouve déjà à la fin, il ne fait rien.
.
sans *
devant - Avance la position dans la source par la première occurrence de .
sans copier aucun caractère, et ajoute .
au nom de la cible. Si .
n'est pas trouvé dans la source, alors avance à la fin de la source et ajoute .
au nom de la cible.
après que le targetMask ait été épuisé, tout .
et {space}
suivant est coupé à la fin du nom cible résultant parce que les noms de fichiers Windows ne peuvent pas se terminer par .
ou {space}
Quelques exemples pratiques
Substituer un caractère en 1ère et 3ème position avant toute extension (ajoute un 2ème ou 3ème caractère s'il n'existe pas encore)
ren * A?Z*
1 -> AZ
12 -> A2Z
1.txt -> AZ.txt
12.txt -> A2Z.txt
123 -> A2Z
123.txt -> A2Z.txt
1234 -> A2Z4
1234.txt -> A2Z4.txt
Modifier l'extension (finale) de chaque fichier
ren * *.txt
a -> a.txt
b.dat -> b.txt
c.x.y -> c.x.txt
Ajouter une extension à chaque fichier
ren * *?.bak
a -> a.bak
b.dat -> b.dat.bak
c.x.y -> c.x.y.bak
Supprimer toute extension supplémentaire après l'extension initiale. Notez que le ?
adéquat doit être utilisé pour préserver le nom complet existant et l'extension initiale.
ren * ?????.?????
a -> a
a.b -> a.b
a.b.c -> a.b
part1.part2.part3 -> part1.part2
123456.123456.123456 -> 12345.12345 (note truncated name and extension because not enough `?` were used)
Identique à ce qui précède, mais filtrez les fichiers dont le nom initial et/ou l'extension dépassent 5 caractères afin qu'ils ne soient pas tronqués. (On peut évidemment ajouter un ?
supplémentaire à chaque extrémité de targetMask pour préserver les noms et extensions jusqu'à 6 caractères)
ren ?????.?????.* ?????.?????
a -> a
a.b -> a.b
a.b.c -> a.b
part1.part2.part3 -> part1.part2
123456.123456.123456 (Not renamed because doesn't match sourceMask)
Modifier les caractères après le dernier _
dans le nom et tenter de préserver l'extension. (Ne fonctionne pas correctement si _
apparaît dans l'extension)
ren *_* *_NEW.*
abcd_12345.txt -> abcd_NEW.txt
abc_newt_1.dat -> abc_newt_NEW.dat
abcdef.jpg (Not renamed because doesn't match sourceMask)
abcd_123.a_b -> abcd_123.a_NEW (not desired, but no simple RENAME form will work in this case)
Tout nom peut être décomposé en composants qui sont délimités par .
Les caractères ne peuvent être ajoutés ou supprimés qu'à la fin de chaque composant. Les caractères ne peuvent pas être supprimés ou ajoutés au début ou au milieu d'un composant tout en préservant le reste avec des jokers. Les substitutions sont autorisées partout.
ren ??????.??????.?????? ?x.????999.*rForTheCourse
part1.part2 -> px.part999.rForTheCourse
part1.part2.part3 -> px.part999.parForTheCourse
part1.part2.part3.part4 (Not renamed because doesn't match sourceMask)
a.b.c -> ax.b999.crForTheCourse
a.b.CarPart3BEER -> ax.b999.CarParForTheCourse
Si les noms courts sont activés, alors un masque source avec au moins 8 ?
pour le nom et au moins 3 ?
pour l'extension correspondra à tous les fichiers car il correspondra toujours au nom court 8.3.
ren ????????.??? ?x.????999.*rForTheCourse
part1.part2.part3.part4 -> px.part999.part3.parForTheCourse
Manque d'utilité/baille ? pour la suppression des préfixes de noms
Ce billet de SuperUser décrit comment un ensemble de barres obliques (/
) peut être utilisé pour supprimer les caractères de tête d'un nom de fichier. Une barre oblique est nécessaire pour chaque caractère à supprimer. J'ai confirmé le comportement sur une machine Windows 10.
ren "abc-*.txt" "////*.txt"
abc-123.txt --> 123.txt
abc-HelloWorld.txt --> HelloWorld.txt
Cette technique ne fonctionne que si les masques source et cible sont entre guillemets. Tous les formulaires suivants sans les guillemets requis échouent avec cette erreur : The syntax of the command is incorrect
REM - All of these forms fail with a syntax error.
ren abc-*.txt "////*.txt"
ren "abc-*.txt" ////*.txt
ren abc-*.txt ////*.txt
Le /
ne peut pas être utilisé pour supprimer les caractères du milieu ou de la fin d'un nom de fichier. Il ne peut supprimer que les caractères de tête (préfixe). Notez également que cette technique ne fonctionne pas avec les noms de dossiers.
Techniquement, le /
ne fonctionne pas comme un joker. Il s'agit plutôt d'une simple substitution de caractères, mais après la substitution, la commande REN reconnaît que /
n'est pas valide dans un nom de fichier, et supprime les barres obliques /
du nom. REN donne une erreur de syntaxe s'il détecte /
au milieu d'un nom de cible.
Bogue RENAME possible - une seule commande peut renommer le même fichier deux fois !
Commençant dans un dossier de test vide :
C:\test>copy nul 123456789.123
1 file(s) copied.
C:\test>dir /x
Volume in drive C is OS
Volume Serial Number is EE2C-5A11
Directory of C:\test
09/15/2012 07:42 PM <DIR> .
09/15/2012 07:42 PM <DIR> ..
09/15/2012 07:42 PM 0 123456~1.123 123456789.123
1 File(s) 0 bytes
2 Dir(s) 327,237,562,368 bytes free
C:\test>ren *1* 2*3.?x
C:\test>dir /x
Volume in drive C is OS
Volume Serial Number is EE2C-5A11
Directory of C:\test
09/15/2012 07:42 PM <DIR> .
09/15/2012 07:42 PM <DIR> ..
09/15/2012 07:42 PM 0 223456~1.XX 223456789.123.xx
1 File(s) 0 bytes
2 Dir(s) 327,237,562,368 bytes free
REM Expected result = 223456789.123.x
Je crois que le masque source *1*
correspond d'abord au nom long du fichier, et le fichier est renommé au résultat attendu de 223456789.123.x
. RENAME continue ensuite à chercher d'autres fichiers à traiter et trouve le fichier nouvellement nommé via le nouveau nom court de 223456~1.X
. Le fichier est alors renommé à nouveau, donnant le résultat final de 223456789.123.xx
.
Si je désactive la génération de noms 8.3, alors le RENAME donne le résultat attendu.
Je n'ai pas encore entièrement déterminé toutes les conditions de déclenchement qui doivent exister pour induire ce comportement étrange. Je craignais qu'il soit possible de créer un RENAME récursif sans fin, mais je n'ai jamais pu en induire un.
Je crois que tout ce qui suit doit être vrai pour induire le bug. Chaque cas bogué que j'ai vu avait les conditions suivantes, mais tous les cas qui remplissaient les conditions suivantes n'étaient pas bogués.
- Les noms courts 8.3 doivent être activés
- Le SourceMask doit correspondre au nom long original.
- Le renommage initial doit générer un nom court qui correspond également au SourceMask
- Le nom court initial renommé doit être trié plus tard que le nom court original (s'il existait ?)