Отримайте найновіший файл у каталозі в Linux


183

Шукаю команду, яка поверне один найновіший файл у каталог.

Не бачити граничного параметра для ls...


1
watch -n1 'ls -Art | tail -n 1'- показує останні останні файли

Більшість відповідей тут аналізують вихід lsабо використання, findбез -print0яких проблематично обробляти набридливі імена файлів. Завжди корисно згадати: BashFAQ099, який дає POSIX відповідь на цю проблему
kvantour

Відповіді:


266
ls -Art | tail -n 1

Не дуже елегантно, але це працює.


2
за допомогою ls -Artls ви також можете переглянути дату файлу.
Йосір

13
Невелика проблема: Ця версія передає весь вихід lsна tail, а потім друкує лише ОСТАННІ рядки. IMHO краще сортувати у порядку зростання та використовувати headзамість цього, як chaosпропонується. Після друку заголовок першого рядка закривається, тому надсилання наступного рядка (фактично наступного блоку) підвищить SIGPIPE і lsтакож вийде.
Дійсно

1
@TrueY Я цілком згоден. Відповідь хаосу краще для ефективності.
dmckee --- кошеня колишнього модератора

2
Зауважте, що це рішення включає каталоги, а також файли. Це може бути добра або погана річ; це залежить від того, чого хоче індивідуальний користувач. Причиною цього я є те, що в оригінальному запитанні написано "файл".
Сілдорет

2
Я думаю, що передбачуваною перевагою використання хвоста замість голови може бути виключення включення рядка, що описує загальну кількість повернених ls.
Пітер Скотт

155
ls -t | head -n1

Ця команда фактично дає останній змінений файл у поточному робочому каталозі.


Еквівалентний моєму, а можливо, і більш ефективному.
dmckee --- кошеня колишнього модератора

не дуже працює для мене, оскільки я спочатку отримую деяку інформацію в моєму лс, але я отримую використання, дякую!
ack

4
@Josir Це можна змінити, щоб включити марку дати ls -tl | head -n 1, і не потрібно проштовхувати всю таблицю через трубу, як це робить моя.
dmckee --- кошеня колишнього модератора

1
@ noɥʇʎԀʎzɐɹƆls -t *.png | head -n1
хаос

4
Це повертає папку, якщо вона остання змінена, використовуйте: ls -Art | head -n1якщо ви конкретно хочете останнього зміненого файлу
achasinh

79

Це рекурсивна версія (тобто вона знаходить останній оновлений файл у певному каталозі чи будь-якому його підкаталозі)

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

Редагувати: використовувати -f 2-замість того, -f 2як запропонував Кевін


5
Ось рішення для Mac:find $DIR -type f -exec stat -lt "%Y-%m-%d" {} \+ | cut -d' ' -f6- | sort -n | tail -1
користувач

2
Проблема полягає в тому, що команда cut обрізає шляхи з пробілами замість -f 2 використовує -f2-, щоб повернути поля 2 до кінця рядка
Кевін

2
Як і в пропозиції хаосу, якщо ви переймете сортування за допомогою sort -nr, ви можете використовувати head -n 1замість цього tail -n 1і трохи підвищити ефективність. (Хоча якщо ви сортуєте рекурсивну знахідку, отримання першого чи останнього рядка не буде повільною частиною.)
destenson

2
Дуже корисний! Мені здається, що це більш привітно, якщо труба до ls:find ./ -type f -printf "%T@ %p\n" -ls | sort -n | cut -d' ' -f 2- | tail -n 1 | xargs -r ls -lah
Саймон

@ версія Mac користувача лише сортує / відображає дату, а не час. Ось виправлена ​​версія:find $DIR -type f -exec stat -lt "%F %T" {} \+ | cut -d' ' -f6- | sort -n | tail -1
йоз

11

Примітка про надійність:

Оскільки символ нового рядка є таким же дійсним, як і будь-яке ім'я файлу, будь-яке рішення, яке спирається на рядки, як head/ tailзасновані, є помилковими.

Для GNU lsінший варіант полягає у використанні --quoting-style=shell-alwaysпараметра та bashмасиву:

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

(додайте -Aпараметр, lsякщо ви також хочете розглянути приховані файли).

Якщо ви хочете обмежитися звичайними файлами (ігнорувати каталоги, фіфоси, пристрої, символьні посилання, сокети ...), вам потрібно буде вдатися до GNU find.

З bash 4.4 або новішими (для readarray -d) та GNU coreutils 8.25 або новішими (для 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]}"

Або рекурсивно:

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

Найкраще тут буде використовувати zshта його глобальні класифікатори, а bashне уникати всіх цих клопотів:

Найновіший звичайний файл у поточному каталозі:

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

У тому числі приховані:

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

Другий останній:

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

Перевірка віку файлу після роздільної здатності символьної посилання:

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

Рекурсивно:

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

Крім того, з compinitувімкненою системою завершення ( і спільнотою) вона Ctrl+Xmстає комплектувачем, який розширюється до найновішого файлу.

Так:

vi Ctrl+Xm

Ви змусите редагувати найновіший файл (ви також отримаєте шанс побачити, який це файл, перш ніж натиснути Return).

vi Alt+2Ctrl+Xm

Для другого найновішого файлу.

vi * .cCtrl+Xm

для найновішого cфайлу.

vi * (.)Ctrl+Xm

для найновішого звичайного файлу (не каталогу, ні fifo / device ...) тощо.


Дякую за zshпоради. Чи можете ви надати посилання на більш детальну інформацію про це в документах zsh?
заморожено

@freezed, див.info zsh qualifiers
Стефан Шазелас

Дякуємо @Stephane Chazelas
заморожено

9

Я використовую:

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

Він дає мені лише ім'я файлу, виключаючи папки.


хіба що в каталозі є лише каталоги
ealfonso

8

ls -lAtr | tail -1

Інші рішення не включають файли, які починаються з '.'.

Ця команда також буде включати '.'і '..', що може бути або не бути тим, що ви хочете:

ls -latr | tail -1


Чи повернеться цей один "". якщо каталог було змінено нещодавно, ніж будь-який файл, що міститься (скажімо, шляхом видалення)? Можливо, це бажана поведінка, а може ні. Але ти прав в будь-якому випадку.
dmckee --- кошеня колишнього модератора


5

Мені подобається echo *(om[1])( zshсинтаксис), оскільки він просто дає ім'я файлу і не викликає жодної іншої команди.


1
Добре працює, якщо ви використовуєте zsh. Ви не використовуєте zsh? Я думаю, що bash є типовим для Ubuntu; ви можете встановити zsh, або ви можете знайти еквівалентну команду для bash.
MikeB

3
Команда - "відлуння"; він просто оцінює його параметри і відправляє їх на стандартний вихід. У цьому випадку у глобальному класифікаторі "om [1]" є "o", що означає впорядкувати файли відповідності по "m", що змінюється часом. І з цього упорядкованого списку візьміть [1], який є першим файлом. Про глобальні
класифікатори

4

Рішення пошуку / сортування працює чудово, поки кількість файлів не стане дійсно великою (як уся файлова система). Замість цього використовуйте awk, щоб просто відслідковувати останній файл:

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]* //'

3

Я особисто вважаю за краще використовувати якомога менше не вбудованих bashкоманд (щоб зменшити кількість дорогих системних викликів fork та exec). Для сортування за датою lsпотрібно дзвонити. Але використання headне дуже потрібне. Я використовую таку підводку (працює лише в системах, що підтримують імена труб):

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

або щоб отримати ім'я найдавнішого файлу

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

(Зверніть увагу на пробіл між двома знаками '<'!)

Якщо також потрібні приховані файли, можна додати аргумент.

Я сподіваюся, що це могло б допомогти.


Ви повинні пояснити, що ім'я файлу зберігається у $ найстаріший / найновіший var. Але +1 за найменшу кількість виделок.
squareatom

@squareatom Я вважав, що прочитане досить добре знає вбудований. Але ти маєш рацію, може, ні. Дякуємо за Ваш коментар!
TrueY

3
Якщо припустити, що ви знаєте, що таке вбудований, ви неправомірно правильні. Але я просто думав над питанням ОП. Вони попросили команду, яка б щось повернула. Технічно ваше рішення нічого не дає. Тож просто додайте "&& echo $
newwest

3

використовуючи рекурсивний варіант R .. Ви можете розглянути це як доповнення для хороших відповідей тут

ls -arRtlh | tail -50

2
ls -t -1 | sed '1q'

Показуватиме останній змінений елемент у папці. З'єднайте, grepщоб знайти останні записи з ключовими словами

ls -t -1 | grep foo | sed '1q'

що таке "1q"? 1є для першого рядка рівним тому, head -n 1що дорівнює q?
HattrickNZ

2

Рекурсивно:

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

1

спробуйте цю просту команду

ls -ltq  <path>  | head -n 1

Якщо ви хочете назву файлу - останню зміну, path = /ab/cd/*.log

Якщо ви хочете ім'я каталогу - остання змінена, path = / ab / cd / * /


1

Припускаючи, що вам не цікаво прихованих файлів, які починаються з a .

ls -rt | tail -n 1

Інакше

ls -Art | tail -n 1


0

Всі ці Ls / хвіст рішення працює прекрасно для файлів в каталозі - ігнорування підкаталоги.

Для включення всіх файлів у пошук (рекурсивно) пошук може бути використаний. gioele запропонував сортувати відформатований вихід пошуку. Але будьте обережні з пробілами (його пропозиція не працює з пробілами).

Це має працювати з усіма іменами файлів:

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

Це сортування за mtime, див. Пошук людини:

%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.

Так просто замінити %Tз , %Cщоб сортувати по CTime.


Ви правильно ставитесь до проблеми білого простору з пропозицією @gioele, але вам потрібно лише додати дефіс до параметра -f, щоб зробити його діапазоном для виправлення, що: find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 2- | tail -n 1 Або, як варіант, зберегти все, крім першого поля: find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 1 --complement | tail -n 1
Аарон,

0

Пошук найактуальнішого файлу у кожному каталозі за зразком, наприклад, підкаталоги робочого каталогу, що мають ім’я, що закінчується на "tmp" (регістр нечутливий):

find . -iname \*tmp -type d -exec sh -c "ls -lArt {} | tail -n 1" \;

0
ls -Frt | grep "[^/]$" | tail -n 1

1
Є й інші відповіді, які забезпечують питання ОП, і вони були опубліковані багато років тому. Опублікувавши відповідь, будь ласка, переконайтесь, що ви додали або нове рішення, або істотно краще пояснення, особливо, відповідаючи на старі питання.
help-info.de

2
@ help-info.de Будь ласка, не голосуйте, щоб видалити відповіді, котрі мають лише код. Вони можуть не бути великими, але видалення - це те, що не відповідає
Machavity

@Machavity - Я сподіваюся, що не провалився, і зробив коментар лише за пізню відповідь.
help-info.de

0

Якщо ви хочете отримати останній змінений файл, включно з будь-якими підкаталогами, ви можете зробити це за допомогою цього маленького oneliner:

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

Якщо ви хочете зробити те ж саме не для змінених файлів, а для файлів, які отримують доступ, вам просто потрібно змінити

% Y параметра з стат команди до % X . І ваша команда для останніх доступних файлів виглядає так:

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

Для обох команд ви також можете змінити параметр var = "1", якщо потрібно перелічити більше ніж один файл.


-1

Мені це теж потрібно було зробити, і я знайшов ці команди. ці роботи для мене:

Якщо ви хочете, щоб останній файл за його датою створення в папці (час доступу):

ls -Aru | tail -n 1  

І якщо ви хочете, щоб останній файл, який має зміни у своєму вмісті (змінити час):

ls -Art | tail -n 1  
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.