Jak napisać skrypt do przenoszenia tylko 20 najstarszych plików z jednego folderu do drugiego? Czy istnieje sposób na pobranie najstarszych plików w folderze?
bash
shell
shell-script
files
timestamps
użytkownik11598
źródło
źródło
atime
(ostatni dostęp),ctime
(ostatnia zmiana uprawnień) imtime
(ostatnia modyfikacja) ... np.ls -t
i znaleźć zaprintf "%T"
korzystaniemtime
... Wydaje się, zgodnie z tym linkiem , że mojeext4
partycje są w stanie obsłużyć daty utworzenia, alels
ifind
, astat
nie mają odpowiednie opcje (jeszcze) ...Odpowiedzi:
Analiza wyniku nie
ls
jest wiarygodna .Zamiast tego użyj
find
do zlokalizowania plików isort
uporządkowania ich według datownika. Na przykład:Co to wszystko robi?
Najpierw
find
polecenia lokalizuje wszystkie pliki i katalogi w bieżącym katalogu (.
), ale nie w podkatalogach bieżącego katalogu (-maxdepth 1
), a następnie drukuje:Znacznik czasu jest ważny. Specyfikator
%T@
formatu dla-printf
podziału naT
, który wskazuje „czas ostatniej modyfikacji” pliku (mtime) i@
, który wskazuje „sekundy od 1970 roku”, w tym ułamkowe sekundy.Przestrzeń jest jedynie arbitralnym ogranicznikiem. Pełna ścieżka do pliku jest taka, że możemy się do niego później odwoływać, a znak NULL jest terminatorem, ponieważ jest to niedozwolony znak w nazwie pliku, a zatem daje nam pewność, że dotarliśmy do końca ścieżki do plik.
Podałem
2>/dev/null
tak, aby pliki, do których użytkownik nie ma uprawnień dostępu, zostały wykluczone, ale komunikaty o błędach ich wykluczenia są pomijane.Wynikiem
find
polecenia jest lista wszystkich katalogów w bieżącym katalogu. Lista jest przesyłana potokowo, dosort
której należy:-z
Traktuj NULL jako znak końca linii zamiast znaku nowej linii.-n
Sortuj numeryczniePonieważ sekundy od 1970 roku zawsze się zwiększają, chcemy pliku, którego znacznik czasu był najmniejszy. Pierwszym wynikiem
sort
będzie linia zawierająca najmniejszy numer znacznika czasu. Pozostaje tylko wyodrębnić nazwę pliku.Wyniki
find
,sort
rurociąg przechodzi przez substytucji procesowej nawhile
którym jest czytać tak, jakby był plik na stdin.while
z kolei wywołujeread
przetwarzanie danych wejściowych.W kontekście
read
ustawiamyIFS
zmienną na nic, co oznacza, że białe znaki nie będą niewłaściwie interpretowane jako separator.read
dowiaduje się-r
, co blokuje ekspansję ucieczki, i-d $'\0'
, co sprawia, że wycofanego z linii ogranicznika NULL, pasujące wyjście z naszejfind
,sort
rurociągu.Pierwszy fragment danych, który reprezentuje najstarszą ścieżkę pliku poprzedzoną znacznikiem czasu i spacją, jest wczytywany do zmiennej
line
. Następnie do wyrażenia stosuje się podstawienie parametrów#*
, które po prostu zastępuje wszystkie znaki od początku łańcucha do pierwszej spacji, w tym spacji, niczym. To usuwa znacznik czasu modyfikacji, pozostawiając tylko pełną ścieżkę do pliku.W tym momencie nazwa pliku jest przechowywana
$file
i możesz z nim zrobić, co chcesz. Kiedy skończysz robić coś z$file
tymwhile
oświadczenie będzie pętli, aread
polecenie zostanie ponownie wykonany, wydobycia następny i następny kawałek nazwy pliku.Czy nie ma prostszego sposobu?
Nie. Prostsze sposoby są wadliwe.
Jeśli użyjesz
ls -t
i potokujesz dohead
lubtail
(lub cokolwiek ), będziesz łamał pliki z nowymi liniami w nazwach plików. Jeślimv $(anything)
następnie pliki z białą spacją w nazwie spowodują uszkodzenie. Jeślimv "$(anything)"
następnie pliki z końcowymi znakami nowej nazwy spowodują uszkodzenie. Jeśli takread
nie-d $'\0'
jest, włamujesz się do plików ze spacjami w ich nazwach.Być może w szczególnych przypadkach wiesz na pewno, że prostszy sposób jest wystarczający, ale nigdy nie powinieneś zapisywać takich założeń w skryptach, jeśli możesz tego uniknąć.
Rozwiązanie
Zadzwoń jak:
Aby przenieść najstarsze 20 plików z
/var/log/foo/
do/mnt/backup/
.Pamiętaj, że dołączam pliki i katalogi. W przypadku plików dodaj tylko
-type f
dofind
wywołania.Dzięki
Dzięki enzotib i Павел Танков za ulepszenia tej odpowiedzi.
źródło
-n
. Przynajmniej w mojej wersji nie porządkuje liczb dziesiętnych. Musisz usunąć kropkę w dacie lub użyć-printf '%TY-%Tm-%TdT%TH:%TM:%TS %p\0' | sort -rz
, dat ISO lub czegoś innego..
musi być dla ciebie nieistotne). Można by to powiedzieć lepiejsort -z -n -t. -k1
.%TS
pokazuje również „część ułamkową”, która byłaby w formie00.0000000000
, więc tracisz również ziarnistość. Najnowszy GNUsort
może rozwiązać ten problem, używając-V
„sortowania wersji”, który będzie obsługiwał tego typu zmiennoprzecinkowe zgodnie z oczekiwaniami.%T@
też by działało, ponieważ jest wypełnione zerami.Najłatwiej jest w Zsh, gdzie można użyć
Om
kwalifikatora globalnego do sortowania dopasowań według daty (od najstarszych) i[1,20]
kwalifikatora, aby zachować tylko 20 pierwszych dopasowań:Dodaj
D
kwalifikator, jeśli chcesz dołączyć również pliki kropek. Dodaj,.
jeśli chcesz dopasować tylko zwykłe pliki, a nie katalogi.Jeśli nie masz Zsh, oto linijka Perla (możesz to zrobić z mniej niż 80 znaków, ale bardziej kosztownie):
Przy użyciu tylko narzędzi POSIX, a nawet bash lub ksh, sortowanie plików według daty jest uciążliwe. Możesz to łatwo zrobić
ls
, ale analizowanie wynikuls
jest problematyczne, więc działa to tylko wtedy, gdy nazwy plików zawierają tylko znaki drukowalne inne niż znaki nowej linii.źródło
Połącz
ls -t
wyjście ztail
lubhead
.Prosty przykład, który działa tylko wtedy, gdy wszystkie nazwy plików zawierają tylko znaki drukowalne inne niż białe znaki i
\[*?
:źródło
ls -1Atr
touch $'foo\n*'
. Co się stanie, jeśli wykonasz mv „$ (ls)” z tym plikiem tam?Możesz użyć do tego GNU find:
Gdzie find wypisuje czas modyfikacji (w sekundach od 1970) i nazwę każdego pliku bieżącego katalogu, dane wyjściowe są sortowane według pierwszego pola, 20 najstarszych jest filtrowanych i przenoszonych do
dest_dir
. Usuń,echo
jeśli testowałeś wiersz poleceń.źródło
Nikt (jeszcze) nie opublikował przykładu bash, który obsługuje osadzone znaki nowej linii (osadzone cokolwiek) w nazwie pliku, więc oto jeden. Przenosi 3 najstarsze (mdate) zwykłe pliki
To jest fragment danych testowych
Oto fragment wyników kontroli
źródło
Najłatwiej jest to zrobić z GNU
find
. Używam go każdego dnia w moim rejestratorze Linux do usuwania nagrań z mojego systemu nadzoru wideo starszego niż jeden dzień.Oto składnia:
Pamiętaj, że
find
określa dzień jako 24 godziny od momentu wykonania. Dlatego pliki ostatnio zmodyfikowane o 23:00 nie zostaną usunięte o 1 w nocy.Możesz nawet łączyć się
find
zcron
, więc usuwanie można zaplanować automatycznie, uruchamiając następującą komendę jako root:Zawsze możesz uzyskać więcej informacji
find
, odwiedzając jego stronę podręcznika:źródło
ponieważ inne odpowiedzi nie pasują do mojej i celu pytania, ta powłoka jest testowana na CentOS 7:
źródło