Je viens de perdre une petite partie de ma collection audio, par une stupide erreur que j'ai commise. :-(
GLADLY J'ai eu une sauvegarde assez récente, mais c'était toujours énervant. À part le vôtre vraiment, l'autre coupable était le méfait mv
, ce qui se manifestera comme suit:
Les fichiers audio avaient un certain schéma:
ARTIST - Some Title YY.mp3
où YY
est la spécification de l'année à 2 chiffres.
mkdir 90<invisible control character>
(Jusqu'à ce moment, je ne savais pas que j'avais en fait tapé un tiers de caractère en excès qui était invisible ...!)
Au lieu d'avoir tout dans un répertoire, je voulais avoir toutes les musiques des années 90 dans un seul répertoire. J'ai donc tapé:
find . -name '* 9?.mp3' -exec mv {} 90 \;
Pas si difficile de savoir ce qui s'est passé hein? : ->
Le résultat (désastreux) était vierge vide répertoire appelé '90 quelque chose »(avec quelque chose étant le caractère de contrôle « invisible ») et un seul fichier appelé « 90 », écrasés n fois.
TOUS LES FICHIERS SONT DISPARUS. :-(( (évidemment)
Wish mv
aurait vérifié à temps si la signature du "fichier" de destination (rappelez-vous sur * NIX: Everything Is A File ) commence par un d------
(par exemple drwxr-xr-x
). Et, bien sûr, si la destination existe . Il existe une variante du scénario ci - dessus, lorsque vous simplement oublié de mkdir
le répertoire en premier. (mais bien sûr, vous supposiez que c'est là ...)
Même notre système d'exploitation pour animaux de compagnie, à commencer par la capitale, W LE FAIT. Vous êtes même invité à spécifier le type de destination (fichier? Répertoire?) Si vous le demandez.
Par conséquent, je me demande si nous * NIXers devons encore nous écrire un " mv
scriptlet" juste pour éviter ce genre de surprises les plus indésirables.
.mp3
devrait être là avec le nom90
, il aurait pu y en avoir un pour lequel vous n'aviez pas de sauvegarde.mv
n'est pas le problème ici, techniquement, il ne sait pas que vous déplacez une série de fichiers. Vous exécutezmv
une seule fois pour chaque fichier. Voilà comment çafind -exec ;
marche. Si vous aviez utiliséfind -exec +
(comme dans certains des commentaires)mv
aurait crié dès qu'il a reçu plus d'un argument.mv
de chaque fichier puisse sembler un peu moins réfléchie au premier abord, ce sera (comme je l'avais dit précédemment) la seule solution sensée une fois que les fichiers source seront dispersés dans divers sous-répertoires. Que dans mon cas de test, les fichiers sources soient tous dans un seul répertoire ne signifie pas que c'est mon cas de test réel . Il s'agit en fait d'une simple simplification, car je pourrai peut-être m'étendre sur ce sujet plus tard. De plus, la lecture des questions prend moins de temps en raison de leur longueur réduite. :)mv
à exiger que la destination existe?mv oldfile newfile
est le moyen de renommer un fichier, et il est stupide de s'attendrenewfile
à exister déjà et à être un répertoire.Réponses:
Vous pouvez ajouter un
/
à la destination si vous souhaitez déplacer des fichiers vers un répertoire. Dans le cas où le répertoire n'existe pas, vous recevrez une erreur:Dans le cas où le répertoire existe, il déplace le fichier dans ce répertoire.
la source
Le GNU coreutils a
mv
déjà une option spécifiant que vous souhaitez déplacer vers un répertoire:-t
/--target-directory
. Si l'argument de cette option n'existe pas,mv
se plaindra au lieu de déplacer tous vos fichiers vers le même nom de fichier.J'aurais écrit votre motionnaire comme suit:
Notez l'utilisation de
+
au lieu de\;
, en regroupant autant de noms de fichiers que possible, ce qui accélère l'exécution.la source
find . -name '* 9?.mp3' -exec sh -c 'exec mv "$@" 90/' sh {} +
De plus, si vous prévoyez généralement d'éviter les remplacements accidentels à l'avenir, il existe l'
-i
option pourmv
. Personnellement, je ne peux penser à aucun inconvénient si vousSi vous devez ensuite écraser quelque chose, passez simplement l'
-f
option.Les alias ne prennent effet que si vous saisissez la commande directement dans un shell interactif, pas pour les cas comme l'appel par
find
. Tu aurais pu courirpuis vous auriez été invité si vous
mv
aviez tenté de remplacer un fichier existant.la source
mv
. Cette "astuce" moins connue fera en sorte que la commande avec la barre oblique inverse ajoutée à elle ignorera toutes les définitions d'alias.find ... -exec mv ...
, alors vous devrez créer~/bin/mv
(ou un autre répertoire approprié) et le faire faire/bin/mv -i "$@"
- carfind ... -exec
ne regarde pas les alias.env mv
. Moins de frappe. :) Comme ma disposition de clavier locale nécessite que la touche MAJ soit enfoncée pour une barre oblique, je préférerais toujours les versions "sans barre oblique" (le cas échéant).mv
dans un endroit au début$PATH
serait une solution plus propre. D'un autre côté, il m'arrive principalement de négligermv
le shell interactif (car cela se produit rapidement). Au moment où je compose quelque chose de plus complexe, commefind
ou unefor
boucle, ou même un script shell, j'ai tendance à effectuer des essais à sec (en utilisantecho
) pour m'assurer de ne pas casser quelque chose. Dans ces cas, je n'ai pas besoin de tenir une mainmv
, car j'y réfléchis déjà.En plus des excellentes réponses ci-dessus, j'aimerais clarifier pourquoi vous n'avez pas obtenu la question de savoir si déplacer les fichiers ou non.
Si vous déplacez un fichier vers un nouveau nom et que ce nom n'est pas un répertoire,
mv
renommez votre fichier sous le nouveau nom.Le problème ici est que vous utilisiez
find
pour exécutermv
une fois par fichier , pas une fois pour tous les fichiers .Si, au lieu de cela, vous aviez fait
mv *90.mp3 90
, alorsmv
aurait échoué avec le message d'erreur que "le fichier cible n'est pas un répertoire".Un autre conseil est d'utiliser la complétion de tabulation lors de la saisie du chemin cible. Il vous montrera si la cible est un répertoire en ajoutant
/
au nom de la cible. Vous pouvez également utilisermv -i
pour vous demander si vous souhaitez remplacer un fichier existant.la source
mv *90.mp3 90
, alors mv aurait échoué avec le message d'erreur que "le fichier cible n'est pas un répertoire". Hah, ouais, pourquoi si compliqué hein? J'utilise votre ligne et je serai heureux. Seulement dans ce cas trivial, cependant. :) Parce que c'est la façon normale de poser mes questions: je les ferais rétrécir par souci de simplicité.find
Jusqu'à présent, personne ne s'est opposé au fait que les fichiers des années 90 pourraient tout aussi bien être dispersés dans divers sous-répertoires que je souhaite également "capturer". Si et seulement s'ils sont toujours dans un répertoire source, votremv
ligne est applicable.mv
se comporte, pas comme une critique de votre choix d'outils.find
etmv
, par exemplefind /music -type d -exec mv {}/*90.mp3 targetdir\;
- mais maintenant je me sens un peu comme si je le compliquais trop, et simplement en utilisant-i
ou-t
est plus efficacefind . -type d -exec mv {}/*9?.mp3 target \;
exemple fonctionnait, il y aurait toujours le risque que lamv
commande ressemble àmv file target
chaque répertoire contenant un seul*9?.mp3
fichier; tous ces fichiers (sauf le dernier) seraient perdus.*.mp3
fichiers d'une arborescence de répertoires, vous pourriezshopt -s globstar
et ensuite exécuter votre commande**/*.mp3
- le**
va agir comme unfind
.En tant que stratégie alternative à usage général, je voudrais suggérer de transformer ce type d'opération en un script temporaire. Je préfère regarder les résultats de
find
et les transformer enmv
commande à la main, en m'assurant de bien comprendre ce que je fais avant d'exécuter. par exemple.Maintenant, je peux parcourir une liste de noms de fichiers et réécrire le contenu du fichier sous forme de commande shell.
ggVGJ
Imv
[esc]
Asomedir/
[esc]
source tmp
sur la ligne de commande.C'est une stratégie conservatrice, mais j'ai été mordu trop souvent par des commandes
-exec
ou des erreurs de frappesed
, ou par des extensions de shell mal comprises, et je préfère adopter une approche lente et cohérente.En d'autres termes: je suis trop lâche pour utiliser
-exec
.la source
:%s/.*/"&"/
étape - parce que, dans ce cas, vous savez que chaque nom de fichier contient au moins un espace.echo mv
au lieu demv
, puis la suppression deecho
si vous êtes satisfait.Une autre option:
c'est la même chose que -i, mais ça ne demandera pas, ça échouera.
la source