Szukam powłoki jednowierszowej, aby znaleźć najstarszy plik w drzewie katalogów.
Szukam powłoki jednowierszowej, aby znaleźć najstarszy plik w drzewie katalogów.
Odpowiedzi:
Działa to (zaktualizowano w celu uwzględnienia sugestii Daniela Anderssona):
find -type f -printf '%T+ %p\n' | sort | head -n 1
find
jest pusta z powodu faktu, że nazwa pliku zawiera nowy wiersz.
Ten jest trochę bardziej przenośny i ponieważ nie opiera się na find
rozszerzeniu GNU -printf
, więc działa również na BSD / OS X:
find . -type f -print0 | xargs -0 ls -ltr | head -n 1
Jedynym minusem jest to, że jest on nieco ograniczony do wielkości ARG_MAX
(co powinno być nieistotne w przypadku większości nowszych jąder). Więc jeśli getconf ARG_MAX
zwrócono więcej niż znaki (262 144 w moim systemie), nie daje to poprawnego wyniku. Nie jest również zgodny z POSIX, ponieważ -print0
i xargs -0
nie jest.
Poniżej przedstawiono kilka rozwiązań tego problemu: Jak znaleźć najnowszy (najnowszy, najwcześniejszy, najstarszy) plik w katalogu? - Wiki Grega
xargs: ls: terminated by signal 13
błąd jako efekt uboczny. Zgaduję, że to SIGPIPE. Nie mam pojęcia, dlaczego nie pojawia się podobny błąd, gdy przesyłam dane wyjściowe sortowania do głowicy w swoim rozwiązaniu.
head
myślę , że to polecenie, które kończy pracę, gdy przeczyta linię, a tym samym „łamie” potok, tak myślę. Błąd sort
nie pojawia się, ponieważ wydaje się, że nie narzeka, ale ls
w innym przypadku.
xargs
trzeba wywołać ls
więcej niż jeden raz. W takim przypadku posortowane dane wyjściowe tych wielokrotnych wywołań kończą się konkatenacją, kiedy należy je połączyć.
ls
go i gałki ocznej najstarszy plik rozwiązanie prawdopodobnie zostanie przekroczony limit długości wiersza poleceń, powodując ls
powoływać się wielokrotnie. Otrzymasz złą odpowiedź, ale nigdy się nie dowiesz.
Następujące polecenia polecenia gwarantują działanie z dowolnymi dziwnymi nazwami plików:
find -type f -printf "%T+ %p\0" | sort -z | grep -zom 1 ".*" | cat
find -type f -printf "%T@ %T+ %p\0" | \
sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //'
stat -c "%y %n" "$(find -type f -printf "%T@ %p\0" | \
sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //')"
Użycie pustego bajtu ( \0
) zamiast znaku wysuwu wiersza ( \n
) zapewnia, że wyjście find będzie nadal zrozumiałe, jeśli jedna z nazw plików zawiera znak wysuwu wiersza.
-z
Przełącznik umożliwia zarówno rodzaj i grep interpretować jedynie jako zerowe bajty wycofanych z linii znaków. Ponieważ nie ma takiego przełącznika na głowę, używamy grep -m 1
zamiast tego (tylko jedno wystąpienie).
Polecenia są uporządkowane według czasu wykonania (mierzonego na moim komputerze).
Pierwsze polecenie będzie najwolniejsze, ponieważ najpierw musi przekonwertować mtime każdego pliku na format czytelny dla człowieka, a następnie posortować te ciągi. Rurociągowanie do kota zapobiega zabarwieniu produktu wyjściowego.
Drugie polecenie jest nieco szybsze. Chociaż nadal wykonuje konwersję daty, sortowanie numeryczne ( sort -n
) sekund, które upłynęły od epoki Uniksa, jest nieco szybsze. sed usuwa sekundy od epoki Uniksa.
Ostatnie polecenie w ogóle nie powoduje konwersji i powinno być znacznie szybsze niż pierwsze dwa. Sama komenda find nie wyświetla czasu mtime najstarszego pliku, więc statystyki są potrzebne.
Chociaż zaakceptowana odpowiedź i inni tutaj wykonują zadanie, jeśli masz bardzo duże drzewo, wszystkie posortują całą wiązkę plików.
Lepiej byłoby, gdybyśmy mogli je po prostu wymienić i śledzić najstarsze, bez konieczności sortowania.
Właśnie dlatego wymyśliłem to alternatywne rozwiązanie:
ls -lRU $PWD/* | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { gsub(/-/,"",$6); if (substr($1,0,1)=="/") { pat=substr($1,0,length($0)-1)"/"; }; if( $6 != "") {if ( $6 < oldd ) { oldd=$6; oldf=pat$8; }; print $6, pat$8; count++;}} END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
Mam nadzieję, że może być pomocna, nawet jeśli pytanie jest nieco stare.
Edycja 1: zmiany te umożliwiają parsowanie plików i katalogów ze spacjami. Jest wystarczająco szybki, aby wydać go w katalogu głównym /
i znaleźć najstarszy plik w historii.
ls -lRU --time-style=long-iso "$PWD"/* | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { gsub(/-/,"",$6); if (substr($0,0,1)=="/") { pat=substr($0,0,length($0)-1)"/"; $6="" }; if( $6 ~ /^[0-9]+$/) {if ( $6 < oldd ) { oldd=$6; oldf=$8; for(i=9; i<=NF; i++) oldf=oldf $i; oldf=pat oldf; }; count++;}} END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
Wyjaśnienie polecenia:
Uruchamianie:
~ $ czas ls -lRU "$ PWD" / * | awk itp
Najstarsza data: 19691231
Plik: /home/.../.../backupold/.../EXAMPLES/how-to-program.txt
Porównywane ogółem: 111438
prawdziwe 0m1.135s
użytkownik 0m0,872s
sys 0m0,760s
EDIT 2: Ta sama koncepcja, lepszym rozwiązaniem przy użyciu find
patrzeć na czas dostępu (używać %T
od pierwszego printf
do czasu modyfikacji lub %C
o zmianie stanu zamiast).
find . -wholename "*" -type f -printf "%AY%Am%Ad %h/%f\n" | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { if ($1 < oldd) { oldd=$1; oldf=$2; for(i=3; i<=NF; i++) oldf=oldf " " $i; }; count++; } END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
EDYCJA 3: Poniższa komenda wykorzystuje czas modyfikacji, a także drukuje przyrostowy postęp, ponieważ wyszukuje coraz starsze pliki, co jest przydatne, gdy masz niepoprawne znaczniki czasu (np. 1970-01-01):
find . -wholename "*" -type f -printf "%TY%Tm%Td %h/%f\n" | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { if ($1 < oldd) { oldd=$1; oldf=$2; for(i=3; i<=NF; i++) oldf=oldf " " $i; print oldd " " oldf; }; count++; } END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
ls
jest złe w skryptach, ponieważ jego dane wyjściowe nie są przeznaczone dla komputerów, formatowanie danych wyjściowych różni się w zależności od implementacji. Jak już wspomniano, find
jest dobry do pisania skryptów, ale może być również dobre dodanie tej informacji przed poinformowaniem o ls
rozwiązaniach.
Użyj ls - strona podręcznika informuje, jak zamówić katalog.
ls -clt | head -n 2
-N 2 jest tak, że nie otrzymujesz „sumy” na wyjściu. Jeśli chcesz tylko nazwę pliku.
ls -t | head -n 1
A jeśli potrzebujesz listy w normalnej kolejności (uzyskanie najnowszego pliku)
ls -tr | head -n 1
Znacznie łatwiejsze niż użycie find, znacznie szybsze i bardziej niezawodne - nie musisz się martwić formatami nazewnictwa plików. Powinien również działać na prawie wszystkich systemach.
find ! -type d -printf "%T@ %p\n" | sort -n | head -n1
sort -n
.
Wydaje się, że przez „najstarsze” większość ludzi przyjęło, że chodziło o „najstarszy czas modyfikacji”. Prawdopodobnie jest to poprawione, zgodnie z najbardziej rygorystyczną interpretacją „najstarszego”, ale w przypadku, gdybyś chciał tego z najstarszym czasem dostępu , zmodyfikowałbym najlepszą odpowiedź w ten sposób:
find -type f -printf '%A+ %p\n' | sort | head -n 1
Zwróć uwagę na %A+
.
set $(find /search/dirname -type f -printf '%T+ %h/%f\n' | sort | head -n 1) && echo $2
find ./search/dirname -type f -printf '%T+ %h/%f\n'
drukuje daty i nazwy plików w dwóch kolumnach.sort | head -n1
zachowuje linię odpowiadającą najstarszemu plikowi.echo $2
wyświetla drugą kolumnę, tj. nazwę pliku.
find -type f -printf '%T+ %p\n' | sort | head -1