69

Я ищу оболочку с одной строкой, чтобы найти самый старый файл в дереве каталогов.

8 ответов8

70

Это работает (обновлено, чтобы включить предложение Даниэля Андерссона):

find -type f -printf '%T+ %p\n' | sort | head -n 1
11

Это немного более переносимо, и потому что оно не зависит от GNU find extension -printf , поэтому оно работает и на BSD / OS X:

find . -type f -print0 | xargs -0 ls -ltr | head -n 1

Единственным недостатком здесь является то, что он несколько ограничен размером ARG_MAX (который не должен иметь значения для большинства новых ядер). Таким образом, если возвращено больше getconf ARG_MAX (262 144 в моей системе), это не даст вам правильного результата. Это также не POSIX-совместимый, потому что -print0 и xargs -0 нет.

Здесь приведены некоторые другие решения этой проблемы: Как найти самый последний (самый новый, самый ранний, самый старый) файл в каталоге? - Грег вики

11

Следующие команды команды гарантированно работают с любыми странными именами файлов:

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/[^ ]* //')"

Использование нулевого байта (\0) вместо символа перевода строки (\n) гарантирует, что вывод find будет по-прежнему понятен в случае, если одно из имен файлов содержит символ перевода строки.

-z позволяет командам sort и grep интерпретировать только нулевые байты как символы конца строки. Поскольку такого переключателя для головы нет, мы используем grep -m 1 (только один случай).

Команды упорядочены по времени выполнения (измерено на моей машине).

  • Первая команда будет самой медленной, поскольку она должна сначала преобразовать mtime каждого файла в читабельный формат, а затем отсортировать эти строки. Трубка к кошке позволяет избежать окрашивания продукции.

  • Вторая команда немного быстрее. Хотя он все еще выполняет преобразование даты, числовая сортировка (sort -n) секунд, прошедших с эпохи Unix, проходит немного быстрее. sed удаляет секунды, начиная с эпохи Unix.

  • Последняя команда не выполняет преобразования вообще и должна быть значительно быстрее, чем первые две. Сама команда find не будет отображать mtime самого старого файла, поэтому требуется статистика.

Связанные справочные страницы: find - grep - sed - sort - stat

5

Хотя принятый ответ и другие здесь делают свою работу, если у вас очень большое дерево, все они будут сортировать всю кучу файлов.

Лучше было бы, если бы мы могли просто перечислить их и отслеживать самые старые, без необходимости сортировки вообще.

Вот почему я придумал это альтернативное решение:

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}'

Я надеюсь, что это может помочь, даже если вопрос немного устарел.


Редактировать 1: эти изменения позволяют анализировать файлы и каталоги с пробелами. Это достаточно быстро, чтобы выдать его в корень / и найти самый старый файл.

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}'

Команда объяснила:

  • ls -lRU - time-style = long-iso "$ PWD"/* перечисляет все файлы (*), длинный формат (l), рекурсивно (R), без сортировки (U), чтобы быть быстрым, и направляет его в awk
  • Awk затем НАЧИНАЕТСЯ с обнуления счетчика (необязательно для этого вопроса) и установки самой старой даты oldd на сегодня, в формате YearMonthDay.
  • Основной цикл первым
    • Возьмите 6-е поле, дату, формат Year-Month-Day и измените его на YearMonthDay (если ваш ls не выводит таким образом, вам может потребоваться его точная настройка).
    • Используя рекурсив, для всех каталогов появятся строки заголовка в виде /directory /here:. Захватите эту строку в переменную pat. (подставляя последний ":" в "/"). И устанавливает $ 6, чтобы избежать использования строки заголовка в качестве допустимой строки файла.
    • если поле $ 6 имеет действительное число, это дата. Сравните это со старой датой oldd.
    • Это старше? Затем сохраните новые значения для старой даты oldd и старого файла oldf. Кстати, oldf - это не только 8-е поле, но и с 8-го до конца. Вот почему цикл для конкатенации от 8-го до NF (конец).
    • Считать авансы на один
    • КОНЕЦ, напечатав результат

Запуск это:

~ $ time ls -lRU "$ PWD"/* | awk и т. д.

Самая старая дата: 19691231

Файл: /home /.../.../backupold /.../EXAMPLES/how-to-program.txt

Всего по сравнению: 111438

реальный 0m1.135s

пользователь 0m0.872s

sys 0m0,760s


РЕДАКТИРОВАТЬ 2: та же концепция, лучшее решение, использующее find для просмотра времени доступа (вместо этого используйте %T с первым printf для времени модификации или %C для изменения статуса ).

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}'

РЕДАКТИРОВАТЬ 3: Команда ниже использует время модификации, а также печатает пошаговый прогресс при поиске старых и старых файлов, что полезно, когда у вас есть неправильные метки времени (например, 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}'
4

Пожалуйста, используйте ls - страница руководства расскажет вам, как заказать каталог.

ls -clt | head -n 2

-N 2 означает, что вы не получите "итого" в выводе. Если вы хотите только имя файла.

ls -t | head -n 1

И если вам нужен список в обычном порядке (получение новейшего файла)

ls -tr | head -n 1

Намного проще, чем использовать find, намного быстрее и надежнее - вам не нужно беспокоиться о форматах имен файлов. Это должно работать почти на всех системах.

2
find ! -type d -printf "%T@ %p\n" | sort -n | head -n1
0

Похоже, что под "самым старым" большинство людей полагало, что вы имели в виду "самое старое время модификации". Это, вероятно, исправлено в соответствии с самым строгим толкованием "самого старого", но в случае, если вам нужен тот, у которого самое старое время доступа , я бы изменил лучший ответ следующим образом:

find -type f -printf '%A+ %p\n' | sort | head -n 1

Обратите внимание на %A+ .

-1
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' печатает даты и имена файлов в двух столбцах.
  • sort | head -n1 сохраняет строку, соответствующую самому старому файлу.
  • echo $2 отображает второй столбец, то есть имя файла.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .