Pobierz najnowszy plik w katalogu w systemie Linux

183

Szukam polecenia, które zwróci pojedynczy najnowszy plik w katalogu.

Nie widzę parametru limitu do ls...

ACK
źródło
1
watch -n1 'ls -Art | tail -n 1'- pokazuje ostatnie pliki
Większość odpowiedzi tutaj analizuje wyjście lslub użycie findbez -print0tego jest problematyczne przy obsłudze irytujących nazw plików. Zawsze warto wspomnieć: BashFAQ099, który daje odpowiedź POSIX na ten problem
kvantour

Odpowiedzi:

266
ls -Art | tail -n 1

Niezbyt eleganckie, ale działa.

dmckee --- kociak ex-moderator
źródło
2
używając ls -Artls możesz również wyświetlić datę pliku.
Josir,
13
Drobny problem: ta wersja przekierowuje wszystkie dane wyjściowe lsdo tail, a następnie wyświetla tylko ostatnią linię. IMHO lepiej jest sortować w kolejności rosnącej i używać headzamiast tego, jak chaossugerowano. Po wydrukowaniu nagłówka pierwszej linii kończy się, więc wysłanie następnej linii (właściwie następnego bloku) spowoduje powstanie SIGPIPE i lsrównież zakończy pracę.
TrueY
1
@TrueY Całkowicie się zgadzam. Odpowiedź Chaosu jest lepsza dla wydajności.
dmckee --- ex-moderator kitten
2
Zwróć uwagę, że to rozwiązanie obejmuje katalogi, a także pliki. To może być dobra lub zła rzecz; zależy to od tego, czego chce indywidualny użytkownik. Powodem, dla którego o tym wspominam, jest to, że pierwotne pytanie brzmi „plik”.
Sildoreth
2
Myślę, że zamierzoną korzyścią z używania tail zamiast head może być wykluczenie włączenia linii opisującej sumę zwracaną przez ls.
Peter Scott,
155
ls -t | head -n1

To polecenie faktycznie podaje ostatnio zmodyfikowany plik w bieżącym katalogu roboczym.

chaos
źródło
Równoważny z moim i prawdopodobnie bardziej wydajny.
dmckee --- kociak ex-moderator
nie działa dla mnie, ponieważ najpierw powtarzam echo niektórych informacji w moim ls, ale otrzymuję informacje o użyciu, dzięki!
potwierdzenie
4
@Josir Można to zmodyfikować, aby uwzględnić datownik z ls -tl | head -n 1, i nie musi przepychać całej tabeli przez potok tak, jak robi to mój.
dmckee --- ex-moderator kitten
1
@ noɥʇʎԀʎzɐɹƆls -t *.png | head -n1
chaos
4
Zwraca folder, jeśli jest to ostatnia modyfikacja, użyj: ls -Art | head -n1jeśli chcesz specjalnie zmodyfikować plik
achasinh
79

To jest wersja rekurencyjna (tzn. Znajduje ostatnio zaktualizowany plik w określonym katalogu lub dowolnym z jego podkatalogów)

find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 2- | tail -n 1

Edycja: używaj -f 2-zamiast -f 2sugerowanych przez Kevina

gioele
źródło
5
Oto rozwiązanie dla komputerów Mac:find $DIR -type f -exec stat -lt "%Y-%m-%d" {} \+ | cut -d' ' -f6- | sort -n | tail -1
użytkownik
2
Problem polega na tym, że obcina dowodzenia cięcie ścieżek ze spacjami zamiast -f 2 Zastosowanie -f2- powrotu pola 2 do końca linii
Kevin
2
Jak w sugestii chaosu, jeśli odwrócisz sortowanie za pomocą sort -nr, możesz użyć head -n 1zamiast tail -n 1i nieznacznie poprawić wydajność. (Chociaż jeśli sortujesz rekursywne znalezisko, pobranie pierwszej lub ostatniej linii nie będzie powolną częścią.)
destenson
2
Bardzo przydatne! Uważam, że jest bardziej przyjazny, jeśli podłączę go do ls:find ./ -type f -printf "%T@ %p\n" -ls | sort -n | cut -d' ' -f 2- | tail -n 1 | xargs -r ls -lah
Simon
Wersja @ użytkownika Mac sortuje / wyświetla tylko datę, a nie godzinę. Oto poprawiona wersja:find $DIR -type f -exec stat -lt "%F %T" {} \+ | cut -d' ' -f6- | sort -n | tail -1
yoz
11

Uwaga dotycząca niezawodności:

Ponieważ znak nowego wiersza jest tak samo ważny jak każdy inny w nazwie pliku, każde rozwiązanie, które opiera się na wierszach, takich jak te oparte na head/ tail, jest wadliwe.

W przypadku GNU lsinną opcją jest użycie --quoting-style=shell-alwaysopcji i bashtablicy:

eval "files=($(ls -t --quoting-style=shell-always))"
((${#files[@]} > 0)) && printf '%s\n' "${files[0]}"

(dodaj -Aopcję, lsjeśli chcesz również uwzględnić pliki ukryte).

Jeśli chcesz ograniczyć się do zwykłych plików (zignoruj ​​katalogi, kolejki linowe, urządzenia, dowiązania symboliczne, gniazda ...), będziesz musiał odwołać się do GNU find.

Z bash 4.4 lub nowszym (dla readarray -d) i GNU coreutils 8.25 lub nowszym (dla cut -z):

readarray -t -d '' files < <(
  LC_ALL=C find . -maxdepth 1 -type f ! -name '.*' -printf '%T@/%f\0' |
  sort -rzn | cut -zd/ -f2)

((${#files[@]} > 0)) && printf '%s\n' "${files[0]}"

Lub rekurencyjnie:

readarray -t -d '' files < <(
  LC_ALL=C find . -name . -o -name '.*' -prune -o -type f -printf '%T@%p\0' |
  sort -rzn | cut -zd/ -f2-)

Najlepiej byłoby tutaj użyć zshi jego kwalifikatorów glob, zamiast bashuniknąć tego całego kłopotu:

Najnowszy zwykły plik w bieżącym katalogu:

printf '%s\n' *(.om[1])

W tym ukryte:

printf '%s\n' *(D.om[1])

Drugi najnowszy:

printf '%s\n' *(.om[2])

Sprawdź wiek pliku po rozwiązaniu dowiązania symbolicznego:

printf '%s\n' *(-.om[1])

Rekurencyjnie:

printf '%s\n' **/*(.om[1])

Ponadto, z compinitwłączonym systemem uzupełniania ( i co), Ctrl+Xmprogram uzupełniający, który rozwija się do najnowszego pliku.

Więc:

vi Ctrl+Xm

Zmusiłby Cię do edycji najnowszego pliku (masz również szansę zobaczyć, który z nich zostanie przed naciśnięciem Return).

vi Alt+2Ctrl+Xm

Dla drugiego najnowszego pliku.

vi * .cCtrl+Xm

dla najnowszego cpliku.

vi * (.)Ctrl+Xm

dla najnowszego zwykłego pliku (nie katalogu, ani fifo / device ...) i tak dalej.

Stephane Chazelas
źródło
Dzięki za zshwskazówki. Czy możesz podać link do szczegółowych informacji na ten temat w dokumentach zsh?
zamrożono
@freezed, patrzinfo zsh qualifiers
Stephane Chazelas
Dzięki @Stephane Chazelas
zamrożono
9

Używam:

ls -ABrt1 --group-directories-first | tail -n1

Daje mi tylko nazwę pliku, z wyłączeniem folderów.

user1195354
źródło
chyba że katalog ma tylko katalogi
ealfonso
8

ls -lAtr | tail -1

Inne rozwiązania nie obejmują plików zaczynających się od '.'.

To polecenie będzie również zawierać '.'i '..', co może być tym, czego chcesz, ale nie musi:

ls -latr | tail -1

Jared Oberhaus
źródło
Czy ten wróci "." czy katalog został zmodyfikowany później niż jakikolwiek znajdujący się w nim plik (powiedzmy przez usunięcie)? Może to pożądane zachowanie, a może nie. Ale tak czy inaczej masz rację.
dmckee --- ex-moderator kitten
6

Skrócony wariant oparty na odpowiedzi dmckee:

ls -t | head -1
Dmytro G. Sergiienko
źródło
ale -1składnia do głowy jest przestarzała już jakiś czas temu i -n 1powinna być używana.
tink
5

Podoba mi się echo *(om[1])( zshskładnia), ponieważ podaje tylko nazwę pliku i nie wywołuje żadnego innego polecenia.

MikeB
źródło
1
Działa dobrze, jeśli używasz zsh. Nie używasz zsh? Myślę, że bash jest domyślnym w Ubuntu; możesz zainstalować zsh lub możesz znaleźć równoważne polecenie dla bash.
MikeB,
3
Polecenie to „echo”; po prostu ocenia swoje parametry i wysyła je na standardowe wyjście. W tym przypadku kwalifikator glob „om [1]” ma „o”, co oznacza, że ​​pasujące pliki są uporządkowane według „m”, czyli czasu modyfikacji. Z tej uporządkowanej listy weź [1], który jest pierwszym plikiem. Możesz przeczytać o kwalifikatorach glob: zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Qualifiers
MikeB,
4

Rozwiązanie find / sort działa świetnie, dopóki liczba plików nie stanie się naprawdę duża (jak cały system plików). Zamiast tego użyj awk, aby po prostu śledzić najnowszy plik:

find $DIR -type f -printf "%T@ %p\n" | 
awk '
BEGIN { recent = 0; file = "" }
{
if ($1 > recent)
   {
   recent = $1;
   file = $0;
   }
}
END { print file; }' |
sed 's/^[0-9]*\.[0-9]* //'
Patrick
źródło
3

Osobiście wolę używać jak najmniejszej bashliczby niezabudowanych poleceń (aby zmniejszyć liczbę kosztownych wywołań systemowych fork i exec). Aby posortować według daty ls, należy zadzwonić. Ale używanie programu headnie jest naprawdę konieczne. Stosuję następującą jednowarstwową (działa tylko na systemach obsługujących rury nazwane):

read newest < <(ls -t *.log)

lub uzyskać nazwę najstarszego pliku

read oldest < <(ls -rt *.log)

(Uwaga na odstęp między dwoma znakami „<”!)

Jeśli ukryte pliki są również potrzebne, można dodać -Aarg.

Mam nadzieję, że to pomoże.

Prawda
źródło
Powinieneś wyjaśnić, że nazwa pliku jest przechowywana w $ najstarszej / najnowszej zmiennej. Ale +1 za najmniejszą liczbę wideł.
squareatom
@squareatom Wydawało mi się, że czytanie jest dość dobrze znane. Ale masz rację, może nie. Dzięki za komentarz!
TrueY
3
Zakładając, że wiesz, co to jest wbudowany, prawdopodobnie masz rację. Ale myślałem tylko o pytaniu OP. Poprosili o polecenie, które coś zwróci. Technicznie rzecz biorąc, Twoje rozwiązanie nic nie wyświetla. Więc po prostu dodaj „&& echo $ newest” lub
coś
3

używając opcji rekurencyjnej R .. możesz to uznać za ulepszenie dobrych odpowiedzi tutaj

ls -arRtlh | tail -50
mebada
źródło
2
ls -t -1 | sed '1q'

Pokaże ostatnio zmodyfikowany element w folderze. Połącz z, grepaby znaleźć najnowsze wpisy ze słowami kluczowymi

ls -t -1 | grep foo | sed '1q'
Richard Servello
źródło
co to jest „1q”? 1jest równoznaczne z pierwszym wierszem head -n 1q?
HattrickNZ
2

Rekurencyjnie:

find $1 -type f -exec stat --format '%Y :%y %n' "{}" \; | sort -nr | cut -d: -f2- | head
Konki
źródło
1

spróbuj tego prostego polecenia

ls -ltq  <path>  | head -n 1

Jeśli chcesz, aby nazwa pliku - ostatnio zmodyfikowana, ścieżka = /ab/cd/*.log

Jeśli chcesz nazwę katalogu - ostatnia modyfikacja, ścieżka = / ab / cd / * /

RICHA AGGARWAL
źródło
1

Zakładając, że nie przejmujesz się ukrytymi plikami zaczynającymi się od .

ls -rt | tail -n 1

Inaczej

ls -Art | tail -n 1
jasonleonhard
źródło
1

Z wbudowanymi tylko Bash, ściśle podążającymi za BashFAQ / 003 :

shopt -s nullglob

for f in * .*; do
    [[ -d $f ]] && continue
    [[ $f -nt $latest ]] && latest=$f
done

printf '%s\n' "$latest"
Benjamin W.
źródło
0

Wszystkie te rozwiązania ls / tail działają doskonale w przypadku plików w formacie katalogu - ignorując podkatalogów.

Aby uwzględnić wszystkie pliki w wyszukiwaniu (rekurencyjnie), można użyć funkcji find. gioele zasugerował sortowanie sformatowanego wyniku wyszukiwania. Uważaj jednak na białe spacje (jego sugestia nie działa w przypadku białych znaków).

Powinno to działać ze wszystkimi nazwami plików:

find $DIR -type f -printf "%T@ %p\n" | sort -n | sed -r 's/^[0-9.]+\s+//' | tail -n 1 | xargs -I{} ls -l "{}"

Sortuje według czasu, zobacz man find:

%Ak    File's  last  access  time in the format specified by k, which is either `@' or a directive for the C `strftime' function.  The possible values for k are listed below; some of them might not be available on all systems, due to differences in `strftime' between systems.
       @      seconds since Jan. 1, 1970, 00:00 GMT, with fractional part.
%Ck    File's last status change time in the format specified by k, which is the same as for %A.
%Tk    File's last modification time in the format specified by k, which is the same as for %A.

Więc po prostu wymienić %Tsię %Cna sortowanie wg ctime.

podstawowy6
źródło
Masz rację co do problemu z białymi znakami z sugestią @gioele, ale wystarczy dodać myślnik do opcji -f, aby ustawić zakres, aby to naprawić: find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 2- | tail -n 1 Lub alternatywnie, zachowaj wszystko oprócz pierwszego pola: find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 1 --complement | tail -n 1
Aaron
0

Znajdowanie najbardziej aktualnego pliku w każdym katalogu według wzorca, np. Podkatalogów katalogu roboczego, które mają nazwę kończącą się na „tmp” (bez rozróżniania wielkości liter):

find . -iname \*tmp -type d -exec sh -c "ls -lArt {} | tail -n 1" \;
xb.
źródło
0
ls -Frt | grep "[^/]$" | tail -n 1
João Fonseca
źródło
1
Istnieją inne odpowiedzi, które zawierają pytanie PO, i zostały one opublikowane wiele lat temu. Pisząc odpowiedź, upewnij się, że dodałeś nowe rozwiązanie lub znacznie lepsze wyjaśnienie, szczególnie w przypadku odpowiedzi na starsze pytania.
help-info.de
2
@ help-info.de Prosimy nie głosować za usuwaniem odpowiedzi zawierających tylko kod. Mogą nie być świetne, ale usuwanie dotyczy rzeczy, które nie są odpowiedziami
Machavity
@Machavity - mam nadzieję, że nie zawiodłem i skomentowałem tylko za późną odpowiedź.
help-info.de
0

Jeśli chcesz pobrać najnowszy zmieniony plik, zawierający również podkatalogi, możesz to zrobić za pomocą tego małego onelinera:

find . -type f -exec stat -c '%Y %n' {} \; | sort -nr | awk -v var="1" 'NR==1,NR==var {print $0}' | while read t f; do d=$(date -d @$t "+%b %d %T %Y"); echo "$d -- $f"; done

Jeśli chcesz zrobić to samo nie dla zmienionych plików, ale dla plików, do których uzyskano dostęp, po prostu musisz zmienić

% R parametrów z stat polecenia do X% . Twoje polecenie dla ostatnio otwieranych plików wygląda następująco:

find . -type f -exec stat -c '%X %n' {} \; | sort -nr | awk -v var="1" 'NR==1,NR==var {print $0}' | while read t f; do d=$(date -d @$t "+%b %d %T %Y"); echo "$d -- $f"; done

W przypadku obu poleceń możesz także zmienić parametr var = "1" , jeśli chcesz wyświetlić więcej niż jeden plik.

OASE Software GmbH
źródło
-1

Też musiałem to zrobić i znalazłem te polecenia. te działają dla mnie:

Jeśli chcesz mieć ostatni plik według daty utworzenia w folderze (czas dostępu):

ls -Aru | tail -n 1  

A jeśli chcesz ostatni plik, który ma zmiany w swojej zawartości (czas modyfikacji):

ls -Art | tail -n 1  
masoomeh vahid
źródło