Déplacer les fichiers et inviter l'utilisateur en cas de noms en double:
Comme le montrent les réponses de Subv3rsion et d' Eric Leschinski , le -newermt
prédicat sélectionne les fichiers modifiés plus récemment que la date (et l'heure facultative) spécifiée comme opérande. Pour rechercher des fichiers
- n'importe où
srcdir
(c'est- à -dire, y compris ses sous-répertoires, leurs sous-répertoires, etc.)
- dernière modification en (par exemple) septembre 2014
- et les déplacer vers
destdir
...tu peux courir:
find srcdir -type f -newermt 2014-08-31 ! -newermt 2014-09-30 -exec mv -i {} destdir/ \;
Dans une -exec
expression, find passe le nom de fichier trouvé à la place de {}
. ;
signifie -exec
que la commande à exécuter et ses arguments ont tous été fournis (dans le cas où des expressions ultérieures sont passées pour rechercher après -exec
les arguments de ce prédicat particulier - voir ci-dessous pour un exemple de cela). ;
doit être échappé car \;
il n'est pas interprété spécialement par le shell. (Sans \
, ;
mettrait fin à la find
commande entière , fonctionnant de la même manière qu'une nouvelle ligne. Même si cette find
commande n'a rien après cette -exec
expression, le fait de ne pas passer l' ;
argument est toujours une erreur de syntaxe.)
Si vous souhaitez simplement répertorier les fichiers - ce qui est conseillé si vous n'êtes pas sûr de la façon dont les anciens e-mails sont stockés ou quels autres fichiers peuvent être présents - omettez -exec
tout ce qui se trouve à droite. (Pour les e-mails, souvent des e-mails de dates différentes sont stockés dans le même fichier; pour quelqu'un dans la situation décrite dans la question ici, je recommande d'étudier comment ils sont stockés avant de déplacer des fichiers.) Si vous souhaitez à la fois imprimer leurs noms et déplacer eux, ajoutez -print
avant -exec
.
mv -i
invite chaque fois qu'un fichier est écrasé à destination, comme cela se produirait si:
- un fichier du même nom existe depuis une sauvegarde précédente, ou
- un fichier du même nom mais d'un sous-répertoire différent de
srcdir
a déjà été déplacé au cours de la même find
opération, ou
- (le moins probable) un fichier du même nom a été créé quelque part au
srcdir
cours de la même find
opération, après que l'original a été déplacé mais assez tôt pour être trouvé une fois find
traversé un sous-répertoire différent.
Autres façons d'invoquer rm
:
Vous disposez d'autres options pour gérer les fichiers avec des noms en double.
- Sans
-i
(c.-à-d. ), Ne demanderait généralement pas l'approbation, mais le ferait si le fichier de destination était en lecture seule. ( peut même réussir à remplacer un fichier en lecture seule parfois, comme si l'utilisateur qui l'exécute est propriétaire du fichier.)mv {} destdir/
mv
mv
- Si vous ne voulez même pas ce degré d'interactivité et que vous souhaitez
mv
toujours (tenter de) écraser des fichiers portant le même nom, utilisez mv -f
.
- Si, au contraire, vous souhaitez ignorer les fichiers source alors qu'il existe déjà un fichier de destination du même nom, utilisez
mv -n
.
mv
accepte les indicateurs -b
et --backup
pour renommer automatiquement les fichiers de même nom qui existent déjà à la destination. Par défaut ~
est ajouté pour produire le nom de sauvegarde, et si un fichier avec le nom et un fichier avec le nom de sauvegarde existent déjà à la destination, le fichier de sauvegarde est écrasé. Cette valeur par défaut peut être remplacée par les options passées lors de l'appel mv
et par les variables d'environnement. Voir man mv
pour plus de détails et l'exemple ci-dessous.
Déplacer les fichiers et créer des sauvegardes en cas de noms en double:
Pour déplacer tous les fichiers, sauvegarder des fichiers avec des noms en double à l'aide d'un ~
suffixe et utiliser des suffixes numérotés lorsque des fichiers existent déjà (afin d'éviter d'écraser quoi que ce soit), exécutez:.~n~
.~
find srcdir -type f -newermt 2014-08-31 ! -newermt 2014-09-30 -exec mv --backup=existing {} destdir/ \;
Si vous avez ignoré des fichiers avec des noms en double et que vous souhaitez savoir lesquels:
Si vous utilisez mv -n
et souhaitez savoir quels fichiers n'ont pas été déplacés car il y avait un autre fichier du même nom, la meilleure façon est probablement d'exécuter à find
nouveau la commande d' origine , sans -exec
et tout à sa droite. Cela imprimera leurs noms.
Il affichera également les noms de tous les fichiers correspondants créés depuis que vous avez exécuté la find .... -exec ...
commande d' origine , mais pour cette application, il n'y en aura généralement aucun puisque vous recherchez des fichiers avec d'anciens temps de modification. Il est possible de donner à un fichier un horodatage de modification plus ancien que son âge réel, avec touch
et d'autres mécanismes, mais cela ne semble pas susceptible de se produire dans ce cas à votre insu.
Sachant immédiatement que les fichiers sont ignorés en raison de noms en double:
mv -n
ne signale pas et ne renvoie aucun code de sortie spécial lorsqu'il s'abstient de déplacer un fichier. Donc, si vous souhaitez être immédiatement informé des fichiers ignorés lors des find
exécutions, vous devrez effectuer une étape distincte pour cela. Une façon est:
find srcdir -type f -newermt 2014-08-31 ! -newermt 2014-09-30 -exec mv -n {} destdir/ \; \
-exec [ -f {} ] \; -exec printf "\`%s' skipped (exists in \`%s')\\n" {} destdir \;
Quelques considérations techniques probablement mineures: cela avertit de manière incorrecte si vousmv
ne parvient pas à copier un fichier pour une raison différente de celle qui existe à la destination et quitte le signalement du succès . Cela semble peu probable, mais je ne suis pas certain que ce soit impossible. Il souffre également potentiellement d'une condition de concurrence : il avertirait lorsqu'il n'y a aucune erreur réelle, si un nouveau fichier du même nom était créé au même endroit pendant la très courte période après le déplacement de l'ancien fichier et avant la vérification à voir si elle a été supprimée. (Compte tenu de l'application, je doute que l'un ou l'autre problème se produise réellement.) Il pourrait être réécrit pour vérifier la destination avantdéplacer le fichier plutôt qu'après: alors la condition de concurrence serait liée aux fichiers de destination nouvellement créés au lieu des fichiers source. Et bien que les erreurs et avertissements signalés par find
ou mv
(ou [
, bien qu'il ne devrait pas y en avoir) soient écrits sur l'erreur standard , notre ...skipped (exists in...
avertissement est écrit sur la sortie standard . Normalement, les deux apparaissent sur votre terminal, mais cela peut être important si vous créez des scripts.
J'ai divisé cette commande sur deux lignes pour une lecture plus facile. Il peut être exécuté de cette façon, ou vous pouvez supprimer le \
et la nouvelle ligne (c'est-à-dire le saut de ligne).
Comment fonctionne cette find
commande?
find
les prédicats peuvent être des tests (comme -type
et -newermt
), utilisés pour leurs valeurs de retour, ou des actions (comme -print
et-exec
), qui sont souvent utilisés pour leurs effets secondaires.
Lorsqu'aucun opérateur (comme -a
pour et , -o
pour ou ) n'est fourni entre les expressions, -a
est implicite. find
utilise une évaluation de court-circuit pour et et ou . (c'est-à-dire ) n'est vrai que si les expressions p et q sont toutes les deux vraies, donc q n'a pas besoin d'être évalué si p est faux. Bien que nous n'y pensions souvent pas en ces termes, c'est pourquoi les tests doivent être vrais pour que les actions ou tests ultérieurs soient évalués. Par exemple, supposonsp q
p -a q
find
se trouve un répertoire. Il est évalué -type f
à faux, il peut donc tout ignorer par la suite.
Comme les tests, les actions sont également évaluées comme vraies ou fausses. De cette façon, -exec
signale si la commande exécutée a quitté le signalement du succès (vrai) ou de l'échec (faux). Nous avons cette chaîne d' -exec
expressions liée à implicite et :
-exec mv -n {} destdir/ \; -exec [ -f {} ] \; -exec printf "\`%s' skipped (exists in \`%s')\\n" {} destdir \;
Cela essaie de déplacer le fichier et, en cas d' mv
échec, s'arrête. Nous ne voulons pas avertir d'un fichier correctement ignoré si un autre problème explique pourquoi il n'a pas été déplacé.
Mais s'il réussit, il exécute alors la [
commande . Comme find
, [
prend en charge son propre type d'expressions passées en arguments. [ -f {} ]
vérifie si l'opérande après -f
(passé à lui find
à la place de {}
) existe (et est un fichier normal), et retourne soit vrai / succès soit faux / échec.
(Les états de sortie de nombreuses commandes sont mieux interprétés comme signifiant un succès ou un échec, mais[
l'état existant existe généralement mieux comme vrai ou faux.)
S'il [
est retourné faux, le fichier a disparu, il a donc été déplacé, il n'y a donc pas besoin de faire quoi que ce soit. Mais s'il [
est retourné faux, le fichier est toujours là. find
Évalue ensuite l' -exec
expression suivante , qui imprime le message d'avertissement.
Lectures complémentaires