Comment déplacer et recréer un dossier en même temps?

9

J'ai un dossier appelé statisticssur un serveur Ubuntu dans lequel les fichiers de données sont régulièrement stockés. Comment puis-je renommer un statisticsdossier en backup-xxrecréant le statisticsdossier pour qu'il soit disponible pour stocker de nouveaux fichiers?

Les fichiers du statisticsdossier sont créés par PHP file_put_contents.

Je préfère renommer le dossier, car il contient de nombreux fichiers statistics.

Googlebot
la source
Au début, je pensais que vous vouliez dire "en même temps" que l'opération devait être "atomique" (dans la mesure du possible).
phk
@phk Oui, c'est exactement ce que je voulais dire.
Googlebot
La terminologie correcte serait "répertoire" et non "dossier" au fait.
Berk Özbalcı

Réponses:

7
mv statistics backup-xx && mkdir statistics

Cela renommerait le statisticsrépertoire existant en backup-xx, et si cela réussit, il continuerait à créer un nouveau statisticsrépertoire.

Pour une opération plus atomique, envisagez de créer un répertoire statistics-001(ou similaire, peut-être en le remplaçant 001par la date d'aujourd'hui dans un format approprié), et un lien symbolique vers celui-ci appelé statistics:

mkdir statistics-001
ln -s statistics-001 statistics

Lorsque vous souhaitez "faire pivoter" ceci afin que les nouvelles données soient placées dans un répertoire propre, créez d'abord le répertoire, puis recréez le statisticslien vers celui-ci:

mkdir statistics-002
ln -sf statistics-002 statistics

mv statistics-001 backup-001

De cette façon, toute écriture de programme dans le statisticsrépertoire (le répertoire que ce lien symbolique) ne sera jamais à 1 ne parviennent pas à le trouver.

Si vous avez besoin d'autorisations spéciales ou de propriété définies sur le répertoire vers lequel vous vous statisticsdirigez, définissez-les avant de (re) créer le lien.

1 Ou plutôt, de cette façon, le temps qu'un programme serait sans répertoire cible valide est minimisé autant que possible en utilisant les outils Unix standard.

Kusalananda
la source
1
Vous pouvez également vouloir chown --reference=backup-xx statistics ; chmod --reference=backup-xx statisticsdéfinir des propriétés et des autorisations. Idéalement, vous feriez cela avant de renommer, donc un mkdir new ; chown ; chmod ; mv stats backup ; mv new statsprocessus de type.
Stephen Harris
@StephenHarris Oui, sur les systèmes qui ont ces drapeaux.
Kusalananda
Ce n'est pas atomique, cependant. C'est proche de l'atomique, mais pas tout à fait.
un CVn le
@ MichaelKjörling Le corrige.
Kusalananda
ln -sfn'est pas atomique. Il est spécifié de dissocier l'ancien lien symbolique puis d'en créer un nouveau, qui est nécessairement non atomique. Au lieu de cela, vous devez créer un lien symbolique temporaire supplémentaire et utiliser la renamefonction (via la mvcommande, par exemple) pour remplacer atomiquement l'ancien. Voir mon approche ici: git.musl-libc.org/cgit/musl/tree/tools/…
R .. GitHub STOP STOPINGING ICE
12

Il n'y a aucun moyen de remplacer atomiquement un répertoire par un autre répertoire. Vous pouvez déplacer l'ancien répertoire puis créer un nouveau répertoire:

mv statistics backup-xx
mkdir statistics

Mais cela laisse une petite fenêtre de temps pendant laquelle statisticsn'existe pas. C'est un problème si un processus peut à tout moment déposer des fichiers dans le répertoire.

Pour remplacer efficacement un répertoire de manière atomique, vous devez utiliser des liens symboliques. Créez un répertoire dont le nom inclut la période de temps depuis le début:

mkdir "statistics-$(date +%Y%m%d)"

(ou comme vous voulez choisir la convention de dénomination des répertoires). Créez un lien symbolique avec un nom fixe vers l'emplacement actuel:

ln -s  statistics

Pour remplacer le répertoire, créez d'abord un nouveau répertoire et un nouveau lien symbolique, puis déplacez-le pour remplacer l'ancien lien symbolique. Notez que ni une plaine mvsur le lien symbolique ni une plaine ln -sne le feront: ils créeraient une entrée dans le répertoire cible. GNU coreutils ln -snfne convient pas non plus car il supprime le lien symbolique existant avant d'en créer un nouveau, ce qui laisse une petite fenêtre de temps pendant laquelle le chemin n'existe pas. Vous pouvez utiliser GNU coreutils mv -Tsur le nouveau lien symbolique.

new_dir="statistics-$(date +%Y%m%d)"
mkdir "$new_dir"
ln -s statistics.new
mv -Tf statistics.new statistics
Gilles 'SO- arrête d'être méchant'
la source
busybox' ln -sfn'est pas non plus atomique, je ne connais aucune implémentation.
phk
1
À côté de phk, les liens symboliques de commentaires ne sont pas non plus sûrs à 100% car un processus en cours peut toujours avoir un descripteur de fichier de répertoire ouvert (cible de lien symbolique) et il pourrait créer plus de nouveaux fichiers dans le répertoire renommé (pensez openat()ou CWD). Je déplacerais seulement le contenu du répertoire vers un nouveau. C'est encore dangereux pour les fichiers ouverts, mais un peu mieux. Dans le doute, utilisez celui logrotatequi doit respecter au mieux ces questions.
rudimeier
1
@phk L' symlinkappel système n'écrasera pas un fichier existant, il est donc impossible de commuter directement un lien symbolique de manière atomique, malheureusement. L' renameappel système écrasera un fichier existant, mais de façon ennuyeuse, il n'existe aucun moyen portable de le faire dans le shell; c'est possible avec GNU coreutils grâce à l' -Toption.
Gilles 'SO- arrête d'être méchant'
3

Ne renommez pas du tout le répertoire. Vous avez dit que vous préférez renommer le répertoire car il contient beaucoup de fichiers. La seule raison pour laquelle je peux penser que vous le voudriez est que la copie des fichiers prendrait trop de temps. Cependant, le déplacement (c'est-à-dire le changement de nom) des fichiers est instantané tant qu'ils sont déplacés vers un emplacement sur le même système de fichiers. Je suppose que c'est ce que vous devez faire, car si vous changez de système de fichiers, mvcela prendra autant de temps que cps'il déplace un répertoire ou son contenu.

Alors, faites simplement:

mkdir backup-xx && mv statistics/* backup-xx

Si vous devez également obtenir des fichiers cachés, vous pouvez faire:

mkdir backup-xx && mv statistics/* statistics/.* backup-xx

Ou, si vous utilisez bash:

shopt -s dotglob; mkdir backup-xx && mv statistics/* statistics/.* backup-xx

De cette façon, le répertoire est toujours là mais vous déplacez toujours son contenu en une opération simple et rapide.

terdon
la source
1

Vous pouvez déplacer le contenu du dossier des statistiques vers un répertoire nouvellement créé plutôt que de déplacer le dossier lui-même. Si vous déplacez un dossier entier, vous devrez exécuter une autre commande pour modifier les autorisations de répertoire.

mkdir -p <path>/backup-xxx
mv statistics/* <path>/backup-xxx/.
Kiran Kumar Annam
la source