Я ищу оболочку с одной строкой, чтобы найти самый старый файл в дереве каталогов.
8 ответов
Это работает (обновлено, чтобы включить предложение Даниэля Андерссона):
find -type f -printf '%T+ %p\n' | sort | head -n 1
Это немного более переносимо, и потому что оно не зависит от 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
нет.
Здесь приведены некоторые другие решения этой проблемы: Как найти самый последний (самый новый, самый ранний, самый старый) файл в каталоге? - Грег вики
Следующие команды команды гарантированно работают с любыми странными именами файлов:
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
Хотя принятый ответ и другие здесь делают свою работу, если у вас очень большое дерево, все они будут сортировать всю кучу файлов.
Лучше было бы, если бы мы могли просто перечислить их и отслеживать самые старые, без необходимости сортировки вообще.
Вот почему я придумал это альтернативное решение:
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}'
Пожалуйста, используйте ls - страница руководства расскажет вам, как заказать каталог.
ls -clt | head -n 2
-N 2 означает, что вы не получите "итого" в выводе. Если вы хотите только имя файла.
ls -t | head -n 1
И если вам нужен список в обычном порядке (получение новейшего файла)
ls -tr | head -n 1
Намного проще, чем использовать find, намного быстрее и надежнее - вам не нужно беспокоиться о форматах имен файлов. Это должно работать почти на всех системах.
find ! -type d -printf "%T@ %p\n" | sort -n | head -n1
Похоже, что под "самым старым" большинство людей полагало, что вы имели в виду "самое старое время модификации". Это, вероятно, исправлено в соответствии с самым строгим толкованием "самого старого", но в случае, если вам нужен тот, у которого самое старое время доступа , я бы изменил лучший ответ следующим образом:
find -type f -printf '%A+ %p\n' | sort | head -n 1
Обратите внимание на %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'
печатает даты и имена файлов в двух столбцах.sort | head -n1
сохраняет строку, соответствующую самому старому файлу.echo $2
отображает второй столбец, то есть имя файла.