Jak znaleźć pliki między dwiema datami za pomocą „find”?

21

Mam konto e-mail, które przeszło 60 GB wiadomości e-mail, a obecnie mam problemy z użyciem klienta poczty e-mail do archiwizacji wiadomości e-mail z zeszłego roku (2011).

Poprzez terminal próbuję użyć find do zlokalizowania plików między 2011-01-01 a 31.12.2011, ale bezskutecznie.

Jak znaleźć pliki między dwiema datami?

W razie potrzeby celem końcowym będzie partia, która przeniesie każdy znaleziony plik, dopasowując przedział dat, do folderu.

Zuul
źródło
@EliahKagan W tym czasie, jeśli pamięć służy, zduplikowane nazwy nie stanowią problemu. Niemniej jednak, jeśli karmisz się, że masz czas, zawsze doceniamy dodatkowe informacje na dany temat :) Również podniosłem twoją odpowiedź, ponieważ zapewnia ona dodatkowy wgląd w ten temat.
Zuul,
@EliahKagan W takim przypadku zachęcam do udzielenia odpowiedzi z praktycznym bezpiecznym działaniem
awaryjnym

Odpowiedzi:

16

Możesz użyć tego skryptu:

#!/bin/bash
for i in $(find Your_Mail_Dir/ -newermt "2011-01-01" ! -newermt "2011-12-31"); do
  mv $i /moved_emails_dir/
done
Octávio Filipe Gonçalves
źródło
6
Dane wyjściowe findnie powinny być przetwarzane w takiej forpętli powłoki , z wyjątkiem sytuacji, gdy gwarantuje się, że żaden plik nie ma pustych spacji w nazwie. -exec, -execdirlub -print0 | xargszwykle powinno się go używać; innym możliwym rozwiązaniem, które zwykle jest znacznie mniej pożądane, ale pozwala na użycie forpętli, jest tymczasowe ustawienie, IFSaby spacja nie była rozpoznawana jako separator pól.
Eliah Kagan
@EliahKagan więc co by wygląd komend jak wtedy: Wystarczy wymienić findz exec? Czy mógłbyś dodać odpowiedź, która dotyczy użycia spacji? Bardzo mile widziane.
SherylHohman,
3
@ SherylHohman Nie, nie używaj execpolecenia. Użyj findpolecenia z -execakcją, aby uruchomić mv, lub cokolwiek, co musisz uruchomić, zgodnie z opisem w odpowiedzi, którą opublikowałem . Kiedy find... -execuruchamia polecenie z odnalezionymi ścieżkami , nie używa powłoki, więc spacje nie powodują dzielenia ani globowania słów . (Możesz opublikować nowe pytanie dotyczące konkretnego przypadku lub zadać dokładnie to, co chcesz wiedzieć.)
Eliah Kagan
@EliahKagan Przepraszam, źle odczytałem twój post - i to od ciebie ! Jesteś niesamowity! Twój post jest doskonały .. i dziękuję za odpowiedź, mimo że to mój własny błąd w czytaniu !!
SherylHohman,
40

Bash znajdź pliki między dwiema datami:

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

Zwraca listę plików, które mają znaczniki czasu po 2010-10-07 i przed 08.10.2014

Bash znajdź pliki sprzed 15 minut do teraz:

find . -type f -mmin -15

Zwraca listę plików, które mają znaczniki czasu po 15 minutach, ale wcześniej.

Bash znajdź pliki między dwoma znacznikami czasu:

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

Zwraca pliki ze znacznikami czasu pomiędzy 2014-10-08 10:17:00i2014-10-08 10:53:00

Eric Leschinski
źródło
10

Przenoszenie plików i monitowanie użytkownika, gdy istnieją zduplikowane nazwy:

Jak pokazują odpowiedzi Subv3rsion i Eric Leschinski , -newermtpredykat wybiera pliki zmodyfikowane później niż data (i opcjonalny czas) określona jako operand. Aby znaleźć pliki

  • w dowolnym miejscu srcdir(tj. łącznie z podkatalogami, ich podkatalogami itp.)
  • ostatnio zmodyfikowano (na przykład) we wrześniu 2014 r
  • i przenieś je dodestdir

... możesz uruchomić:

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

W -execwyrażeniu find podaje nazwę pliku znalezioną zamiast {}. ;oznacza, -execże polecenie, które ma zostać wykonane, i wszystkie jego argumenty, zostały podane (w przypadku, gdy kolejne wyrażenia są przekazywane do znalezienia po -execargumentach tego konkretnego predykatu - patrz przykład tego poniżej). ;należy uciec, ponieważ \;nie jest to specjalnie interpretowane przez powłokę. (Bez \, ;zakończyłoby całą findkomendę, działając tak samo jak nowa linia. Mimo że to findpolecenie nie ma nic po tym -execwyrażeniu, nieprzekazanie ;argumentu jest nadal błędem składniowym.)

Jeśli chcesz tylko wyświetlić listę plików - co jest wskazane, jeśli nie masz pewności, jak są przechowywane stare wiadomości e-mail lub jakie inne pliki mogą być obecne - pomiń -execi wszystko po prawej stronie. (W przypadku wiadomości e-mail często wiadomości e-mail z różnych dat są przechowywane w tym samym pliku; dla kogoś w sytuacji opisanej w pytaniu tutaj zalecam sprawdzenie, w jaki sposób są przechowywane przed przeniesieniem jakichkolwiek plików.) Jeśli chcesz wydrukować ich nazwy i przenieść dodaj je -printwcześniej -exec.

mv -i wyświetla monity za każdym razem, gdy plik zostanie zastąpiony w miejscu docelowym, na przykład, jeśli:

  • plik o tej samej nazwie istnieje z poprzedniej kopii zapasowej, lub
  • plik o tej samej nazwie, ale z innego podkatalogu srcdirzostał już przeniesiony podczas tej samej findoperacji, lub
  • (najmniej prawdopodobne) plik o tej samej nazwie został utworzony gdzieś srcdirpodczas tej samej findoperacji, po przeniesieniu oryginału, ale wystarczająco szybko, aby go znaleźć, gdy findprzejdzie on przez inny podkatalog.

Inne sposoby wywoływania rm:

Istnieją inne opcje obsługi plików o zduplikowanych nazwach.

  • Bez -i(tj. ) Zwykle nie monitowałby o zatwierdzenie, ale zrobiłby to, gdyby plik docelowy był tylko do odczytu. ( czasami może nawet zastąpić plik tylko do odczytu, na przykład jeśli użytkownik, który go uruchomił, jest właścicielem pliku).mv {} destdir/mvmv
  • Jeśli nie chcesz tego stopnia interaktywności i mvzawsze chcesz (próbować) zastąpić pliki o identycznych nazwach, użyj mv -f.
  • Jeśli natomiast chcesz pominąć pliki źródłowe, gdy istnieje już plik docelowy o tej samej nazwie, użyj mv -n.
  • mvakceptuje flagi -bi, --backupaby automatycznie zmieniać nazwy plików o identycznych nazwach, które już istnieją w miejscu docelowym. Domyślnie ~jest dodawany w celu utworzenia nazwy kopii zapasowej, a jeśli plik o nazwie i plik z nazwą kopii już istnieją w miejscu docelowym, plik kopii zapasowej jest zastępowany. To ustawienie domyślne można zastąpić opcjami przekazanymi podczas wywoływania mvoraz zmiennymi środowiskowymi. Zobacz man mvszczegóły i przykład poniżej.

Przenoszenie plików i tworzenie kopii zapasowych w przypadku zduplikowanych nazw:

Aby przenieść wszystkie pliki, ~wykonaj kopię zapasową plików o zduplikowanych nazwach za pomocą sufiksu i użyj sufiksów numerowanych, gdy pliki już istnieją (aby uniknąć nadpisania czegokolwiek), uruchom:.~n~.~

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

Jeśli pominąłeś pliki o zduplikowanych nazwach i chcesz wiedzieć, które:

Jeśli używasz mv -ni chcesz wiedzieć, które pliki nie zostały przeniesione, ponieważ istniał inny plik o tej samej nazwie, prawdopodobnie najlepszym sposobem jest findponowne uruchomienie oryginalnej komendy bez -execi wszystko po prawej stronie. Spowoduje to wydrukowanie ich nazw.
Spowoduje to również wydrukowanie nazw wszystkich pasujących plików utworzonych od czasu uruchomienia oryginalnej find .... -exec ...komendy, ale w przypadku tej aplikacji zwykle nie będzie żadnych, ponieważ szukasz plików ze starymi czasami modyfikacji. Możliwe jest nadanie plikowi znacznika czasu modyfikacji starszego niż jego rzeczywisty wiek, z touchinnymi mechanizmami, ale wydaje się, że w tym przypadku nie zdarzy się to bez Twojej wiedzy.

Natychmiastowa znajomość pomijania plików z powodu zduplikowanych nazw:

mv -nnie zgłasza ani nie zwraca żadnego specjalnego kodu wyjścia , gdy powstrzymuje się od przeniesienia pliku. Więc jeśli chcesz być natychmiast informowany o pomijanych plikach podczas finduruchamiania, musisz zrobić dla tego osobny krok. Jednym ze sposobów jest:

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 \; 

Kilka prawdopodobnie drobnych względów technicznych: Ostrzega to niepoprawnie, jeśli mvnie uda się skopiować pliku z innego powodu niż istniejący w miejscu docelowym i zakończy raportowanie . Wydaje się to mało prawdopodobne, ale nie jestem pewien, czy to niemożliwe. Potencjalnie cierpi również z powodu wyścigu : ostrzegałby, gdy nie wystąpił prawdziwy błąd, gdyby nowy plik o tej samej nazwie został utworzony w tym samym miejscu w bardzo krótkim czasie po przeniesieniu starego pliku i przed sprawdzeniem, czy sprawdź, czy został usunięty. (Ze względu na zastosowanie, wątpię, czy kiedykolwiek będzie problemem faktycznie występuje.) To może być przepisany sprawdzić cel przedprzeniesienie pliku zamiast po: wtedy warunek wyścigu będzie odnosił się do nowo utworzonych plików docelowych zamiast plików źródłowych. I podczas gdy błędy i ostrzeżenia zgłaszane przez findlub mv(lub [, chociaż nie powinny być, żadne) nie będą zapisywane jako standardowe błędy , nasze ...skipped (exists in...ostrzeżenie jest zapisywane na standardowe wyjście . Zwykle oba pojawiają się na twoim terminalu, ale może to mieć znaczenie, jeśli piszesz.

Podzieliłem to polecenie na dwa wiersze, aby ułatwić czytanie. Można go uruchomić w ten sposób lub można usunąć \znak nowej linii (tj. Podział linii).

Jak działa to findpolecenie?

findpredykaty mogą być testami (podobnymi -typei -newermt), używanymi do zwracanych wartości, lub działaniami (podobnymi -printi -exec), które są często stosowane ze względu na ich skutki uboczne.

Implikuje się, że między wyrażeniami nie podano żadnego operatora (takiego jak -afor i , -ofor lub ) -a. findstosuje ocenę zwarcia dla i i lub . (tj. ) jest prawdziwe tylko wtedy, gdy oba wyrażenia p i q są prawdziwe, więc q nie trzeba oceniać, jeśli p jest fałszywe. Chociaż często nie myślimy o tym w tych kategoriach, dlatego testy muszą być prawdziwe, aby kolejne działania lub testy mogły zostać ocenione. Załóżmy na przykład, że pojawia się katalog. Zwraca wartość false, więc może później pominąć wszystko.p qp -a qfind-type f

Podobnie jak testy, działania oceniają również na prawda lub fałsz. W ten sposób -execzgłasza, czy wykonane polecenie zakończyło raportowanie powodzenie (prawda) lub niepowodzenie (fałsz). Mamy ten łańcuch -execwyrażeń związanych z niejawnymi i :

-exec mv -n {} destdir/ \; -exec [ -f {} ] \; -exec printf "\`%s' skipped (exists in \`%s')\\n" {} destdir \;

Próbuje przenieść plik, a jeśli mvzgłosi awarię, zatrzymuje się. Nie chcemy ostrzec o poprawnie pominiętym pliku, jeśli jakiś inny problem polegał na tym, że nie został on przeniesiony.

Ale jeśli to się udało, to wtedy działa na [komendę . Podobnie find, [obsługuje własny rodzaj wyrażeń przekazywanych jako argumenty. [ -f {} ]sprawdza, czy operand po -f(przekazany do niego findzamiast {}) istnieje (i jest zwykłym plikiem), i zwraca albo wartość prawda / sukces, albo fałsz / błąd.
(Statusy wyjścia wielu poleceń najlepiej interpretować jako oznaczające sukces lub porażkę, ale [status istnienia zwykle najlepiej interpretować jako prawda lub fałsz).

Jeśli zostanie [zwrócony false, plik zniknie, więc został przeniesiony, więc nie trzeba nic robić. Ale jeśli [zwróci wartość false, plik nadal istnieje. Następnie findocenia następne -execwyrażenie, które drukuje komunikat ostrzegawczy.

Dalsza lektura

Eliah Kagan
źródło
Kiedy mam czas, mam nadzieję, aby dodać sekcję o względy wydajności oraz -exec ... +z mv -t, kiedyś wkrótce.
Eliah Kagan