Come trovare file tra due date usando "trova"?


21

Ho un account e-mail che ha superato 60 GB di e-mail e attualmente sto riscontrando molti problemi nell'utilizzare un client e-mail per archiviare le e-mail dell'anno scorso (2011).

Tramite il terminale, sto tentando di utilizzare find per individuare i file tra il 01-01-2011 e il 2011-12-31, ma senza risultati.

Come posso trovare file tra due date?

Se pertinente, l'obiettivo finale sarà un batch che sposta ogni file trovato, corrispondente all'intervallo di date, in una cartella.


@EliahKagan Al momento, se la memoria serve, i nomi duplicati non erano un problema. Tuttavia, se si nutre di avere il tempo, vengono sempre apprezzate ulteriori informazioni su un determinato argomento :) Inoltre, ho votato a favore della tua risposta in quanto fornisce ulteriori informazioni su questo argomento.
Zuul,

@EliahKagan In tal caso, ti incoraggio a fornire una risposta con il pratico fail-safe che hai evidenziato :)
Zuul,

Risposte:


16

Puoi usare questo script:

#!/bin/bash
for i in $(find Your_Mail_Dir/ -newermt "2011-01-01" ! -newermt "2011-12-31"); do
  mv $i /moved_emails_dir/
done

6
L'output di findnon dovrebbe essere elaborato in un forloop di shell come questo, tranne quando è garantito che nessun file abbia spazi vuoti nel suo nome. -exec, -execdiro -print0 | xargsdovrebbe invece essere utilizzato in genere; un'altra possibile soluzione, che di solito è molto meno desiderabile ma consente di utilizzare un forloop, è quella di impostare temporaneamente in IFSmodo che uno spazio non venga riconosciuto come separatore di campo.
Eliah Kagan,

@EliahKagan quindi come sarebbe il comando allora: basta sostituire findcon exec? Ti dispiacerebbe aggiungere una risposta che affronta l'uso degli spazi .. ?? Molto apprezzato.
SherylHohman,

3
@SherylHohman No, non usare il execcomando. Utilizzare un findcomando con l' -execazione da eseguire mvo qualunque cosa sia necessario eseguire, come descritto nella risposta che ho pubblicato . Quando find... -execesegue il tuo comando con i nomi dei percorsi trovati, non usa una shell, quindi gli spazi non attivano la suddivisione delle parole o il globbing . (Potresti voler pubblicare una nuova domanda sul tuo caso specifico o chiedere esattamente cosa vuoi sapere.)
Eliah Kagan,

@EliahKagan Siamo spiacenti, ho letto male il tuo post - e che è stato da te ! Sei fantastico! Il tuo post è eccellente ..e grazie per aver risposto, anche se è stato un mio errore di lettura !!
SherylHohman,

40

Bash trova i file tra due date:

find . -type f -newermt 2010-10-07 ! -newermt 2014-10-08

Restituisce un elenco di file che hanno i timestamp dopo il 2010-10-07 e prima del 2014-10-08

Bash trova i file di 15 minuti fa fino ad ora:

find . -type f -mmin -15

Restituisce un elenco di file che hanno i timestamp dopo 15 minuti fa ma prima di adesso.

Bash trova i file tra due timestamp:

find . -type f -newermt "2014-10-08 10:17:00" ! -newermt "2014-10-08 10:53:00"

Restituisce i file con timestamp tra 2014-10-08 10:17:00e2014-10-08 10:53:00


10

Spostamento dei file e richiesta all'utente in presenza di nomi duplicati:

Come mostrano le risposte di Subv3rsion ed Eric Leschinski , il -newermtpredicato 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 sudestdir

... puoi eseguire:

find srcdir -type f -newermt 2014-08-31 ! -newermt 2014-09-30 -exec mv -i {} destdir/ \;

In -execun'espressione, find passa il nome file trovato al posto di {}. ;significa -execche il comando da eseguire, e i suoi argomenti, sono stati tutti forniti (nel caso in cui le espressioni successive vengano passate per trovare dopo -execgli 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 findcomando, funzionando come una nuova riga. Anche se questo findcomando non ha nulla dopo questa -execespressione, 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 -exece 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 -printprima -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 findoperazione, oppure
  • (molto probabilmente) un file con lo stesso nome è stato creato da qualche parte srcdirdurante la stessa findoperazione, dopo che l'originale è stato spostato ma abbastanza presto per essere trovato una volta che findattraversa 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/mvmv
  • Se non si desidera nemmeno quel grado di interattività e si desidera mvsempre (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.
  • mvaccetta i flag -be --backupper 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 mve dalle variabili di ambiente. Vedere man mvper 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 -ne 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 findnuovamente il comando originale , senza -exece 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 touche 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 -nnon 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' findesecuzione, 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 mvnon 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 findo 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 findcomando?

findi predicati possono essere test (come -typee -newermt), usati per i loro valori di ritorno, o azioni (come -printe -exec), che sono spesso usati per i loro effetti collaterali.

Quando nessun operatore (come -afor e , -ofor o ) viene fornito tra le espressioni, -aè implicito. findutilizza 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 qp -a qfind-type f

Come i test, anche le azioni vengono valutate come vere o false. In questo modo, -execsegnala se il comando eseguito è uscito riportando successo (vero) o fallimento (falso). Abbiamo questa catena di -execespressioni 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 mvsegnala 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 findposto 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 findvaluta l' -execespressione successiva , che stampa il messaggio di avviso.

Ulteriori letture


Quando avrò il tempo, spero di aggiungere una sezione sulle considerazioni sulle prestazioni e -exec ... +conmv -t , a breve.
Eliah Kagan,
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.