Як рекурсивно знайти останній модифікований файл у каталозі?


242

Здається, що lsне сортує файли правильно під час рекурсивного дзвінка:

ls -altR . | head -n 3

Як я можу знайти останній змінений файл у каталозі (включаючи підкаталоги)?


Відповіді:


357
find . -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "

Для величезного дерева може бути важко sortзберегти все в пам’яті.

%T@дає вам час модифікації, як часова мітка unix, sort -nсортує чисельно, tail -1приймає останній рядок (найвища часова мітка), cut -f2 -d" "відсікає перше поле (мітка часу) від виводу.

Редагувати: Як -printfімовірно, лише для GNU, використання також і ajreals stat -c. Хоча можна зробити те ж саме на BSD, параметри форматування різні ( -f "%m %N"здавалося б)

І я пропустив частину множини; якщо ви хочете більше , то в останній файл, просто заглиблюватися хвіст аргумент.


7
Якщо замовлення має значення, ви можете переключити використання sort -rn | head -3замість sort -n | tail -3. Одна версія надає файли від найдавніших до найновіших, а друга - від найновіших до найстаріших.
Дон Фолкнер

3
У мене був величезний каталог (десь десять тисяч невеликих файлів), і я хвилювався про продуктивність, але ... ця команда виконується менше ніж за одну секунду! Чудово, велике спасибі !!! :-)
lucaferrario

2
"Для величезного дерева може бути важко зберегти все в пам'яті". sortстворюватимуть тимчасові файли (in /tmp) за потребою, тому я не думаю, що це хвилює.
Володимир Пантелєєв

1
змінивши його на: -printf '%T@ %Tb %Td %TY %p\n'дасть вам штамп дати (якщо потрібно) (подібний до ls)
bshea

1
Я вважаю таке коротше і з більш інтерпретаційним результатом:find . -type f -printf '%TF %TT %p\n' | sort | tail -1
1717 року

129

Після відповіді на @ plundra , ось версія BSD та OS X:

find . -type f -print0 | xargs -0 stat -f "%m %N" |
sort -rn | head -1 | cut -f2- -d" "

1
Є чи BSD / OS X findпідтримка +замість \;? Тому що це робить те ж саме (передаючи декілька файлів як параметри), без -print0 | xargs -0труби.
DevSolar

Що робити, якщо я хочу отримати останні 5 або n кількість файлів, змінених у порядку зменшення?
хуншань

@khunshan змінити head -1наhead -5
Emerson Farrugia

20

Замість сортування результатів та збереження лише останніх модифікованих ви можете використати awk для друку лише того, який має найбільший час модифікації (в unix час):

find . -type f -printf "%T@\0%p\0" | awk '
    {
        if ($0>max) {
            max=$0; 
            getline mostrecent
        } else 
            getline
    } 
    END{print mostrecent}' RS='\0'

Це має бути швидшим способом вирішити вашу проблему, якщо кількість файлів досить велика.

Я використовував символ NUL (тобто '\ 0'), оскільки теоретично ім'я файлу може містити будь-який символ (включаючи пробіл та новий рядок), але це.

Якщо у вас немає таких патологічних імен файлів у вашій системі, ви також можете використовувати символ нового рядка:

find . -type f -printf "%T@\n%p\n" | awk '
    {
        if ($0>max) {
            max=$0; 
            getline mostrecent
        } else 
            getline
    } 
    END{print mostrecent}' RS='\n'

Крім того, це працює і в mawk.


Це можна легко адаптувати, щоб зберегти три останніх.
Призупинено до подальшого повідомлення.

1
Це не працює mawk, стандартна альтернатива Debian.
січня

Ні, але в такому випадку ви можете використовувати символ нового рядка, якщо він вас не турбує;)
marco

10

У мене виникли проблеми з пошуком останнього зміненого файлу під Solaris 10. Там findнемає printfможливості та statнедоступний. Я виявив таке рішення, яке добре працює для мене:

find . -type f | sed 's/.*/"&"/' | xargs ls -E | awk '{ print $6," ",$7 }' | sort | tail -1

Щоб показати ім'я файлу, також використовуйте

find . -type f | sed 's/.*/"&"/' | xargs ls -E | awk '{ print $6," ",$7," ",$9 }' | sort | tail -1

Пояснення

  • find . -type f знаходить і перераховує всі файли
  • sed 's/.*/"&"/' загортає ім'я шляху в лапки, щоб обробляти пробіли
  • xargs ls -Eнадсилає процитований шлях ls, -Eопція гарантує повернення повної часової позначки (формат рік-місяць-день година-хвилина-секунди-наносекунд )
  • awk '{ print $6," ",$7 }' витягує лише дату та час
  • awk '{ print $6," ",$7," ",$9 }' дата, час та назва файлу
  • sort повертає файли, відсортовані за датою
  • tail -1 повертає лише останній змінений файл

9

Здається, це працює добре навіть із підкаталогами:

find . -type f | xargs ls -ltr | tail -n 1

У разі занадто великої кількості файлів уточнити знахідку.


1
-lВаріант lsздається непотрібним. Просто -trздається достатнім.
Acumenus

6
Здається, це
сортується

1
У випадку, якщо в шляхах до файлів є пробіли, краще:find . -type f -print0 | xargs -0 ls -ltr | tail -n 1
Періодичне обслуговування

Це не знаходить останні файли для мене.
K.-Michael Aye

1
Подумайте, що це перерви, якщо у назві файлів є пробіли
waferthin

7

Показує останній файл із часовою міткою, що читається людиною:

find . -type f -printf '%TY-%Tm-%Td %TH:%TM: %Tz %p\n'| sort -n | tail -n1

Результат виглядає приблизно так:

2015-10-06 11:30: +0200 ./foo/bar.txt

Щоб показати більше файлів, замініть -n1на більшу кількість


5

Я постійно використовую щось подібне, а також список топ-k останніх змінених файлів. Для великих дерев каталогів можна набагато швидше уникнути сортування . Що стосується лише топ-1 останнього зміненого файлу:

find . -type f -printf '%T@ %p\n' | perl -ne '@a=split(/\s+/, $_, 2); ($t,$f)=@a if $a[0]>$t; print $f if eof()'

У каталозі, що містить 1,7 мільйона файлів, я отримую найсвіжіший за 3.4 секунди, прискорення 7.5x проти рішення 25.5s за допомогою сортування.


Дуже круто: я просто обмінявся останнім друком з: system ("ls -l $ f"), якщо eof (), щоб побачити дату також приємно.
Мартін Т.

@MartinT. : чудово, і ласкаво просимо. Мені дивно, що люди мають цей інстинкт сортувати речі (O (n log n)), коли доступний метод O (n). Це здається єдиною відповіддю, що уникає подібного роду. До речі, мета команди, яку я запропонував, - це просто знайти шлях останнього файлу. Ви можете створити псевдонім команди в своїй оболонці (наприклад, як lastfile), а потім можете робити все, що завгодно, з результатом, наприклад ls -l $(lastfile .), або open $(lastfile .)(на Mac) тощо.
П'єр Д

Ой, я виправлений: нижче бачу ще одну відповідь (@marco). +1.
П’єр Д

4

Це дає відсортований список:

find . -type f -ls 2>/dev/null | sort -M -k8,10 | head -n5

Згорніть порядок, помістивши в команду сортування '-r'. Якщо ви хочете лише назви файлів, вставте "awk" {print $ 11} '| " перед '| голова'


3

У Ubuntu 13 це робить наступне, можливо, швидше, оскільки він перевертає сортування і використовує "голову" замість "хвіст", зменшуючи роботу. Щоб показати 11 найновіших файлів у дереві:

знайти. -тип f -printf '% T @% p \ n' | сортувати -n -r | голова -11 | вирізати -f2- -d "" | sed -e 's, ^. / ,,' | xargs ls -U -l

Це дає повний перелік ls без повторного сортування та упускає надокучливий './', який 'find' ставить на кожне ім’я файлу.

Або як функція bash:

treecent () {
  local numl
  if [[ 0 -eq $# ]] ; then
    numl=11   # Or whatever default you want.
  else
    numl=$1
  fi
  find . -type f -printf '%T@ %p\n' | sort -n -r | head -${numl} |  cut -f2- -d" " | sed -e 's,^\./,,' | xargs ls -U -l
}

І все-таки більшість робіт було виконано оригінальним рішенням плюндри. Дякую плюндру.


3

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

Ось невеликий сценарій, щоб зробити це швидше:

#!/bin/sh

CURRENT_DIR='.'

zob () {
    FILE=$(ls -Art1 ${CURRENT_DIR} | tail -n 1)
    if [ ! -f ${FILE} ]; then
        CURRENT_DIR="${CURRENT_DIR}/${FILE}"
        zob
    fi
    echo $FILE
    exit
}
zob

Це рекурсивна функція, яка отримує останній змінений елемент каталогу. Якщо цей елемент є каталогом, функція викликається рекурсивно і здійснює пошук у цьому каталозі тощо.


3

Я вважаю наступне коротшим і з більш інтерпретованим результатом:

find . -type f -printf '%TF %TT %p\n' | sort | tail -1

Зважаючи на фіксовану тривалість стандартизованих дат у форматі ISO, лексикографічне сортування є нормальним, і нам не потрібна -nопція щодо сортування.

Якщо ви хочете знову видалити часові позначки, ви можете використовувати:

find . -type f -printf '%TFT%TT %p\n' | sort | tail -1 | cut -f2- -d' '

2

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

find . -type f -print0 | xargs -0 stat -f "%m %N" | sort -n | tail -1 | cut -f2- -d" " 

2

Це рекурсивно змінює час модифікації всіх каталогів у поточному каталозі на найновіший файл у кожному каталозі:

for dir in */; do find $dir -type f -printf '%T@ "%p"\n' | sort -n | tail -1 | cut -f2- -d" " | xargs -I {} touch -r {} $dir; done

1
Це погано розбивається, якщо будь-які dirs містять пробіли - потрібно встановити IFS і використовувати лапки: IFS = $ '\ n'; для dir в $ (знайти ./ -тип d); робити відлуння "$ dir"; знайти "$ dir" -типу f -printf '% T @ "% p" \ n' | сортувати -n | хвіст -1 | вирізати -f2- -d "" | xargs -I {} touch -r {} "$ dir"; зроблено;
Енді Лі Робінсон

2

Цей простий кліп також буде працювати:

ls -1t | head -1

Ви можете змінити -1 на кількість файлів, які потрібно перелічити


10
Ні, це не буде, оскільки це не рекурсивно.
arataj

1

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

find . -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" " | sed 's/.*/"&"/' | xargs ls -l

1

Наступна команда працювала над Solaris:

find . -name "*zip" -type f | xargs ls -ltr | tail -1 

1

Ігнорування прихованих файлів - з приємним та швидким штампом часу

$ find . -type f -not -path '*/\.*' -printf '%TY.%Tm.%Td %THh%TM %Ta %p\n' |sort -nr |head -n 10

Результат

Добре обробляє пробіли у назви файлів - не те, що їх слід використовувати!

2017.01.25 18h23 Wed ./indenting/Shifting blocks visually.mht
2016.12.11 12h33 Sun ./tabs/Converting tabs to spaces.mht
2016.12.02 01h46 Fri ./advocacy/2016.Vim or Emacs - Which text editor do you prefer?.mht
2016.11.09 17h05 Wed ./Word count - Vim Tips Wiki.mht

Більше

Більше find бажання перейти за посиланням.


1

Для пошуку файлів у / target_directory та всіх його підкаталогах, які були змінені за останні 60 хвилин:

$ find /target_directory -type f -mmin -60

Для пошуку останніх модифікованих файлів, відсортованих у зворотному порядку часу оновлення (тобто спочатку останніх оновлених файлів):

$ find /etc -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort -r


0

Я написав пакет pypi / github для цього питання, тому що мені також потрібно було рішення.

https://github.com/bucknerns/logtail

Встановити:

pip install logtail

Використання: хвости змінені файли

logtail <log dir> [<glob match: default=*.log>]

Usage2: відкриває останній змінений файл у редакторі

editlatest <log dir> [<glob match: default=*.log>]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.