Spostamento dei file e richiesta all'utente in presenza di nomi duplicati:
Come mostrano le risposte di Subv3rsion ed Eric Leschinski , il -newermt
predicato seleziona i file modificati più di recente rispetto alla data (e all'ora facoltativa) specificata come operando. Per trovare i file
- ovunque in
srcdir
(cioè, comprese le sue sottodirectory, le loro sottodirectory, ecc.)
- ultima modifica (ad esempio) a settembre 2014
- e spostali su
destdir
... puoi eseguire:
find srcdir -type f -newermt 2014-08-31 ! -newermt 2014-09-30 -exec mv -i {} destdir/ \;
In -exec
un'espressione, find passa il nome file trovato al posto di {}
. ;
significa -exec
che il comando da eseguire, e i suoi argomenti, sono stati tutti forniti (nel caso in cui le espressioni successive vengano passate per trovare dopo -exec
gli argomenti di quel particolare predicato - vedi sotto per un esempio di questo). ;
deve essere evitato in \;
quanto non è interpretato appositamente dalla shell. (Senza \
, ;
finirebbe l'intero find
comando, funzionando come una nuova riga. Anche se questo find
comando non ha nulla dopo questa -exec
espressione, non riuscire a passare l' ;
argomento è ancora un errore di sintassi.)
Se vuoi solo elencare i file - il che è consigliabile se non sei sicuro di come siano archiviate le vecchie e-mail o quali altri file possano essere presenti - ometti -exec
e tutto a destra. (Per le e-mail, spesso le e-mail di date diverse sono archiviate nello stesso file; per qualcuno nella situazione descritta nella domanda qui, consiglio di indagare su come sono memorizzati prima di spostare qualsiasi file.) Se si desidera sia stampare i loro nomi che spostare loro, aggiungere -print
prima -exec
.
mv -i
viene richiesto ogni volta che un file viene sovrascritto nella destinazione, ad esempio se:
- esiste un file con lo stesso nome da un backup precedente o
- un file con lo stesso nome ma da una diversa sottodirectory di
srcdir
è già stato spostato durante la stessa find
operazione, oppure
- (molto probabilmente) un file con lo stesso nome è stato creato da qualche parte
srcdir
durante la stessa find
operazione, dopo che l'originale è stato spostato ma abbastanza presto per essere trovato una volta che find
attraversa una sottodirectory diversa.
Altri modi per invocare rm
:
Hai altre opzioni su come gestire i file con nomi duplicati.
- Senza
-i
(cioè, ), di solito non richiederebbe l'approvazione, ma lo farebbe se il file di destinazione fosse di sola lettura. ( può persino riuscire a sovrascrivere un file di sola lettura a volte, ad esempio se l'utente che lo esegue possiede il file.)mv {} destdir/
mv
mv
- Se non si desidera nemmeno quel grado di interattività e si desidera
mv
sempre (tentare di) sovrascrivere file con nomi identici, utilizzare mv -f
.
- Se, al contrario, si desidera saltare i file di origine quando esiste già un file di destinazione con lo stesso nome, utilizzare
mv -n
.
mv
accetta i flag -b
e --backup
per rinominare automaticamente i file con nomi identici già esistenti nella destinazione. Per impostazione predefinita, ~
viene aggiunto per produrre il nome del backup e se un file con il nome e un file con il nome del backup esiste già nella destinazione, il file di backup viene sovrascritto. Questa impostazione predefinita può essere ignorata dalle opzioni passate durante l'invocazione mv
e dalle variabili di ambiente. Vedere man mv
per i dettagli e l'esempio di seguito.
Spostamento dei file e creazione di backup in caso di nomi duplicati:
Per spostare tutti i file, eseguire il backup dei file con nomi duplicati utilizzando un ~
suffisso e utilizzare suffissi numerati quando i file esistono già (in modo da evitare di sovrascrivere nulla), eseguire:.~n~
.~
find srcdir -type f -newermt 2014-08-31 ! -newermt 2014-09-30 -exec mv --backup=existing {} destdir/ \;
Se hai saltato i file con nomi duplicati e vuoi sapere quali:
Se usi mv -n
e vuoi sapere quali file non sono stati spostati perché c'era un altro file con lo stesso nome, il modo migliore è probabilmente quello di eseguire find
nuovamente il comando originale , senza -exec
e tutto alla sua destra. Questo stamperà i loro nomi.
Stamperà anche i nomi di tutti i file corrispondenti creati da quando hai eseguito il find .... -exec ...
comando originale , ma per questa applicazione in genere non ce ne sarà nessuno poiché stai cercando file con tempi di modifica precedenti. È possibile assegnare a un file un timestamp di modifica più vecchio della sua età reale, con touch
e altri meccanismi, ma ciò non sembra probabile che si verifichi in questo caso a tua insaputa.
Sapendo immediatamente come i file vengono saltati a causa di nomi duplicati:
mv -n
non segnala né restituisce alcun codice di uscita speciale quando si astiene dallo spostare un file. Quindi, se vuoi essere immediatamente informato dei file saltati durante l' find
esecuzione, dovrai fare un passo separato per quello. Un modo è:
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 \;
Alcune considerazioni tecniche probabilmente minori: ciò avvisa in modo errato se mv
non riesce a copiare un file per un motivo diverso da quello esistente nella destinazione e termina con esito positivo . Sembra improbabile, ma non sono sicuro che sia impossibile. Inoltre, potenzialmente subisce una condizione di competizione : avviserebbe quando non si verifica alcun errore reale, se un nuovo file con lo stesso nome fosse creato nello stesso posto durante il tempo molto breve dopo che il vecchio file è stato spostato e prima del controllo in vedere se è stato rimosso. (Considerando l'applicazione, dubito che uno o l'altro dei problemi si verificherebbe mai.) Potrebbe essere riscritto per verificare la destinazione primaspostando il file anziché dopo: la condizione della competizione verrebbe correlata ai file di destinazione appena creati anziché ai file di origine. E mentre gli errori e gli avvisi segnalati da find
o mv
(o [
, anche se non dovrebbero essercene) verranno scritti nell'errore standard , il nostro ...skipped (exists in...
avviso viene scritto nell'output standard . Normalmente entrambi appaiono sul tuo terminale, ma questo può importare se stai scrivendo.
Ho diviso quel comando su due righe per facilitare la lettura. Può essere eseguito in questo modo oppure è possibile rimuovere la \
e la nuova riga (ovvero l'interruzione di riga).
Come funziona quel find
comando?
find
i predicati possono essere test (come -type
e -newermt
), usati per i loro valori di ritorno, o azioni (come -print
e -exec
), che sono spesso usati per i loro effetti collaterali.
Quando nessun operatore (come -a
for e , -o
for o ) viene fornito tra le espressioni, -a
è implicito. find
utilizza una valutazione di corto circuito per e e o o . (cioè, ) è vero solo se le espressioni p e q sono entrambe vere, quindi non è necessario valutare q se p è falso. Sebbene spesso non ci pensiamo in questi termini, è per questo che i test devono essere veri per le successive azioni o test da valutare. Ad esempio, supponiamo che arrivi su una directory. Valuta falso, quindi può saltare tutto in seguito.p q
p -a q
find
-type f
Come i test, anche le azioni vengono valutate come vere o false. In questo modo, -exec
segnala se il comando eseguito è uscito riportando successo (vero) o fallimento (falso). Abbiamo questa catena di -exec
espressioni connesse con implicite e :
-exec mv -n {} destdir/ \; -exec [ -f {} ] \; -exec printf "\`%s' skipped (exists in \`%s')\\n" {} destdir \;
Questo tenta di spostare il file e, se mv
segnala errori, si interrompe. Non vogliamo avvisare di un file saltato correttamente se qualche altro problema fosse il motivo per cui non è stato spostato.
Ma se ha esito positivo, esegue quindi il [
comando . Ad esempio find
, [
supporta il proprio tipo di espressioni passate come argomenti. [ -f {} ]
controlla se l'operando after -f
(passato al find
posto di {}
) esiste (ed è un file normale) e restituisce true / success o false / failure.
(Gli stati di uscita di molti comandi sono meglio interpretati come indicativi di successo o fallimento, ma lo [
stato di esistenza è generalmente interpretato come vero o falso.)
Se [
restituito falso, il file scompare, quindi è stato spostato, quindi non è necessario fare nulla. Ma se [
restituito falso, il file è ancora lì. Quindi find
valuta l' -exec
espressione successiva , che stampa il messaggio di avviso.
Ulteriori letture