Donc, stupide et impatient, j'ai utilisé le script suivant sur mon serveur 19.04 pour tenter de déplacer un tas de fichiers vidéo dans des dossiers avec des préfixes:
dirs=(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
shopt -s nocasematch
for file in *
do
for dir in "${dirs[@]}"
do
if [ -d "$file" ]; then
echo 'this is a dir, skipping'
break
else
if [[ $file =~ ^[$dir] ]]; then
echo "----> $file moves into -> $dir <----"
mv "$file" "$dir"
break
fi
fi
done
done
Aucune idée de l'endroit où cela s'est mal passé, mais au lieu de déplacer les fichiers vers des dossiers, il est allé vers une sortie singulière.
----> a1.ts moves into -> A <----
----> a2.ts moves into -> A <----
----> a3.ts moves into -> A <----
----> a4.ts moves into -> A <----
----> a5.ts moves into -> A <----
----> c1.ts moves into -> C <----
----> c2.ts moves into -> C <----
----> c3.ts moves into -> C <----
----> c4.ts moves into -> C <----
----> c5.ts moves into -> C <----
Heureusement, j'ai arrêté le processus (CTRL + C) dès que j'ai remarqué que ça ne se passait pas comme prévu et que je n'ai pas parcouru tout le dossier.
Alors maintenant, j'ai ces fichiers A
et C
, qui sont moins d'un Go, et à première vue, c'est une seule vidéo.
Il y a 50 Go non comptabilisés dans l'utilisation totale du disque du dossier lui-même, mais l'espace disque global de l'ordinateur est resté le même. Me faisant penser que les fichiers ne sont pas supprimés?
Toute aide appréciée, merci :)
Edit: les fichiers sont réellement partis, il ne reste que le dernier fichier à écrire, il a juste fallu un certain temps pour que les informations d'utilisation du disque se mettent à jour .. moral de l'histoire, exécutez vos scripts sur des fichiers fictifs avant!
la source
A
,B
etc., existaient-ils avant d'exécuter le script? Sinon, vous venez de renommer les fichiers. Tous les fichiers dont les noms ont commencé para
ouA
ont été renommésA
, donc seul le dernier fichier renommé a survécu, les autres sont remplacés. Appeler une variabledir
ne crée pas de répertoire!mv "$file" "$dir/"
, avec un suivi/
; alors si$dir
n'existe pas,mv
sera erreur au lieu de renommage$file
à$dir
. Considérez égalementmv -i
etmv -n
. Et faites toujours unmkdir -p
avant de bouger, pour faire bonne mesure.Réponses:
Je pense que c'est le problème: vous devriez avoir créé les répertoires A, B, C ... Z. Si vous l'avez fait, la
mv
commande aurait dû déplacer les fichiers vers ces répertoires.Sinon, la
mv
commande déplace les fichiers vers des fichiers portant ces noms, A, B, C ... et je pense que c'est ce que vous avez fait.Pour rendre le shellscript plus sûr, vous devez lui faire créer les répertoires (s'ils ne sont pas déjà là) avant de commencer le déplacement.
Si vous voulez que les choses deviennent encore plus sûres, vous pouvez également utiliser
mv
l'-i
optionla source
touch
serait-il un bon substitut pourmkdir
éviter les conflits en cas d'exécution multiple du script?touch
crée un fichier si le nom n'existe pas. Il ne fera donc pas ce que vous voulez dans ce cas.mkdir -p
peut gérer plusieurs fois l'utilisation du script.mv
plus sûr est de prendre l'habitude d'ajouter une barre oblique de fin au nom de la cible lorsque la cible est un répertoire, c'estmv "$file" "$dir/"
@Sudodus a déjà expliqué ce qui n'a pas fonctionné, mais voici une version plus simple de votre script pour la prochaine fois:
Explication
for letter in {a..z}; do
:{a..z}
s'étend à toutes les lettres minuscules entrea
etz
:Donc, cela itérera sur toutes les lettres minuscules, en enregistrant chacune sous
$letter
.dir=${letter^}
: la syntaxe${var^^}
renvoie le contenu de la variable$var
avec le premier caractère en majuscule (puisque cela n'a qu'un seul caractère, c'est tout ce dont nous avons besoin). Donc, si$letter
esta
, alors${letter^^}
estA
, et$dir
sera donc la version majuscule du courant$letter
.mkdir -p -- "$dir"
: créez le répertoire. S'il existe déjà, ne faites rien (-p
). Le--
signifie la fin des options et est utile pour se protéger contre les noms commençant par-
.mv -- "$letter"* "${letter^}"* "$dir"
: déplacer chaque fichier (ou répertoire) vers la cible appropriée.Le problème avec cela, c'est qu'il déplacera également tous les répertoires que vous pourriez avoir. Il ne déplacera pas les répertoires cibles, car soit ils n'existent pas encore, soit vous essayez de les déplacer vers eux-mêmes, mais tous les répertoires existants qui ne sont pas le répertoire cible seront déplacés.
Si c'est un problème, vous devrez faire quelque chose comme ceci:
la source
${letter^}
et${letter^^}
, et s'ils sont identiques, pourquoi les${letter^^}
remplacer$dir
?${var^}
majuscule uniquement la première lettre, tandis que${var^^}
toutes les lettres sont mises en majuscule . Cela ne fait aucune différence ici car$letter
il n'a qu'une seule lettre.$dir
dans lamv
commande. (Dans sa forme actuelle, il échouera si un fichier préexiste avec un nom en majuscule d'une seule lettre)Au lieu de vérifier chaque fichier par rapport à un tableau de dictionnaire qui crée beaucoup d'itérations, vous pouvez comparer les fichiers aux modèles.
Tri très basique:
la source
Sauvegardez dans votre .bashrc:
la source
-n Do not overwrite an existing file. (The -n option overrides any previous -f or -i options.)
que la balise -n sera avant de suivre les balises. Le --backup = numéroté créera un double de chaque droit, n'est-ce pas un peu exagéré (et énergie / consommation d'espace) lors du traitement de fichiers vidéo très volumineux (téraoctets parlants). Merci !Pour mémoire, quelques façons de ne pas
mv
écraser les fichiers existants:Si vous souhaitez vous déplacer dans un répertoire, ajoutez une barre oblique à la cible, c'est-à-dire utilisez à la
mv "$file" "$dir"/
place demv "$file" "$dir"
. S'il$dir
n'existe pas ou n'est pas un répertoire,mv
se plaindra:Cela semble faire l'appel système
rename("a", "z/")
, donc il devrait être à l'abri des vulnérabilités de temps de vérification à temps d'utilisation, au cas où quelqu'un manipulerait le même ensemble de fichiers en même temps.Vous pouvez également utiliser
mv -t "$dir" "$file"
. Encore une fois, il se plaindra s'il$dir
ne s'agit pas d'un répertoire.Utilisez l'
-n
option pour éviter d'écraser les fichiers existants:Cela ne l'empêchera pas de renommer le premier fichier, mais il ne le supprimera pas avec les autres.
Cela semble appeler un simple
rename()
, donc il pourrait ne pas être sûr avec une manipulation simultanée. (Il yrenameat2()
aurait un drapeau pour empêcher l'écrasement.)la source
Bien que ce ne soit apparemment pas le cas pour vous, il est possible que vous puissiez le faire sans perdre les fichiers. Cela nécessiterait l'une des deux choses suivantes:
Les systèmes de fichiers Unix permettent à plusieurs entrées de répertoire de se référer exactement au même contenu de fichier . C'est ce qu'on appelle un « lien dur ». Vous pouvez créer des liens durs avec la
ln
commande, sans l'-s
option commune (douce / symbolique). Tant qu'il existe au moins un lien dur vers le contenu du fichier, il ne sera pas réutilisé par le système de fichiers.(Remarque: les autorisations s'appliquent généralement au contenu du fichier, pas à l'entrée de répertoire. C'est pourquoi un utilisateur ordinaire peut parfois supprimer un fichier appartenant à
root
, mais ne pas y écrire. L'opération de suppression modifie le dossier, pas le fichier lui-même. )Le système de fichiers ne réutilisera pas non plus le contenu du fichier tant qu’au moins un processus a ouvert le fichier. Même si aucune entrée de répertoire n'existe, le système de fichiers ne considérera pas l'espace comme libre jusqu'à ce qu'aucun processus ne l'ouvre. Le fichier peut être récupéré à partir du système
/proc/<pid>/fd
de fichiers virtuelroot
tant que le fichier reste ouvert. (Merci @fluffysheap.)la source