Come spostare e ricreare una cartella contemporaneamente?


9

Ho una cartella chiamata statisticsin un server Ubuntu in cui i file di dati vengono regolarmente memorizzati. Come posso rinominare la statisticscartella backup-xxmentre ricrea la statisticscartella per renderla disponibile per la memorizzazione di nuovi file?

I file nella statisticscartella sono creati da PHP file_put_contents.

Preferisco rinominare la cartella, in quanto ci sono molti file nella statisticscartella.


All'inizio ho pensato che volevi dire "allo stesso tempo" che l'operazione doveva essere "atomica" (per quanto possibile).
phk,

@phk Sì, è esattamente quello che volevo dire.
Googlebot,

A proposito, la terminologia corretta sarebbe "directory" e non "cartella".
Berk Özbalcı,

Risposte:


7
mv statistics backup-xx && mkdir statistics

Ciò rinominerebbe la statisticsdirectory esistente in backup-xxe, se ciò dovesse riuscire, continuerebbe a creare una nuova statisticsdirectory.

Per un'operazione più atomica, considera la creazione di una directory statistics-001(o simile, magari sostituendola 001con la data odierna in un formato adatto), e un link simbolico ad essa chiamato statistics:

mkdir statistics-001
ln -s statistics-001 statistics

Quando si desidera "ruotare" questo in modo che i nuovi dati vadano in una directory pulita, creare prima la directory, quindi ricreare il statisticscollegamento ad essa:

mkdir statistics-002
ln -sf statistics-002 statistics

mv statistics-001 backup-001

In questo modo, qualsiasi programma di scrittura per la statisticsdirectory (cioè la directory che questo simbolico punta puntano a) non potrà mai 1 non riescono a trovarlo.

Se sono necessarie autorizzazioni speciali o proprietà impostate sulla directory che statisticspunta, impostarle prima di (ri) creare il collegamento.

1 O meglio, in questo modo, il tempo in cui un programma sarebbe senza una directory di destinazione valida è minimizzato il più praticamente possibile usando gli strumenti Unix standard.


1
Potresti anche voler chown --reference=backup-xx statistics ; chmod --reference=backup-xx statisticsimpostare proprietà e autorizzazioni. Idealmente lo faresti prima di rinominare, quindi mkdir new ; chown ; chmod ; mv stats backup ; mv new statsdigita un processo.
Stephen Harris,

@StephenHarris Sì, sui sistemi che hanno tali flag.
Kusalananda

Questo non è atomico, però. È vicino all'atomico, ma non del tutto.
un CVn

@ MichaelKjörling Risolto.
Kusalananda

ln -sfnon è atomico. È specificato per scollegare il vecchio symlink e poi crearne uno nuovo, che è necessariamente non atomico. Invece è necessario creare un ulteriore link simbolico temporaneo e utilizzare la renamefunzione (tramite il mvcomando, ad esempio) per sostituire atomicamente quella precedente. Vedi il mio approccio qui: git.musl-libc.org/cgit/musl/tree/tools/…
R .. GitHub

12

Non c'è modo di sostituire atomicamente una directory con un'altra directory. È possibile spostare la vecchia directory quindi creare una nuova directory:

mv statistics backup-xx
mkdir statistics

Ma questo lascia una piccola finestra di tempo durante la quale statisticsnon esiste. Questo è un problema se un processo può far cadere i file nella directory in qualsiasi momento.

Per sostituire in modo atomico efficace una directory, è necessario utilizzare collegamenti simbolici. Creare una directory il cui nome includa il periodo di tempo dall'inizio:

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

(o comunque desideri scegliere la convenzione di denominazione delle directory). Creare un collegamento simbolico con un nome fisso per la posizione corrente:

ln -s  statistics

Per sostituire la directory, creare prima una nuova directory e un nuovo collegamento simbolico, quindi spostarlo per sovrascrivere il vecchio collegamento simbolico. Si noti che né una semplice mvsul collegamento simbolico né una semplice ln -sfaranno questo: creerebbero una voce all'interno della directory di destinazione. Neanche i coreutils di GNU ln -snfsono adatti perché rimuovono il symlink esistente prima di crearne uno nuovo, che lascia una piccola finestra temporale durante la quale il percorso non esiste. Puoi usare i GNU coreutils mv -Tsul nuovo link simbolico.

new_dir="statistics-$(date +%Y%m%d)"
mkdir "$new_dir"
ln -s statistics.new
mv -Tf statistics.new statistics

busybox' ln -sfinoltre non è atomico, non conosco alcuna implementazione.
phk,

1
Oltre ai commenti di phk, i link simbolici non sono sicuri al 100% perché un processo in esecuzione potrebbe avere ancora un descrittore di file di directory aperto (target symlink) e potrebbe creare più nuovi file nella directory rinominata (pensaci openat()o CWD). Sposterei solo il contenuto della directory in una nuova. Non è ancora sicuro per quanto riguarda i file aperti, ma un po 'meglio. In dubbio l'uso logrotateche dovrebbe rispettare al meglio tali problemi.
Rudimeier,

1
@phk La symlinkchiamata di sistema non sovrascriverà un file esistente, quindi è impossibile cambiare direttamente un collegamento simbolico atomicamente, sfortunatamente. La renamechiamata di sistema sovrascriverà un file esistente, ma fastidiosamente non c'è modo portatile per farlo nella shell; è possibile con coreutils GNU grazie -Tall'opzione.
Gilles 'SO- smetti di essere malvagio' il

3

Non rinominare affatto la directory. Hai detto che preferisci rinominare la directory perché ha molti file. L'unica ragione per cui riesco a pensare che vorresti questo è perché la copia dei file richiederebbe troppo tempo. Tuttavia, lo spostamento (ovvero la ridenominazione) dei file è istantaneo purché vengano spostati in una posizione sullo stesso file system. Suppongo che questo sia ciò che devi fare dal momento che se stai cambiando i file system, mvimpiegherà tanto tempo quanto cpnon importa se si sta spostando una directory o il suo contenuto.

Quindi, basta fare:

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

Se devi anche ottenere file nascosti, puoi fare:

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

Oppure, se si utilizza bash:

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

In questo modo, la directory è sempre lì ma si sposta comunque il suo contenuto in un'operazione semplice e veloce.


1

È possibile spostare il contenuto della cartella delle statistiche in una directory appena creata anziché spostare la cartella stessa. Se si sposta l'intera cartella, è necessario eseguire un altro comando per modificare le autorizzazioni della directory.

mkdir -p <path>/backup-xxx
mv statistics/* <path>/backup-xxx/.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.