Я ищу оболочку с одной строкой, чтобы найти самый старый файл в дереве каталогов.
Я ищу оболочку с одной строкой, чтобы найти самый старый файл в дереве каталогов.
Ответы:
Это работает (обновлено, чтобы включить предложение Даниэля Андерссона):
find -type f -printf '%T+ %p\n' | sort | head -n 1
find
пуста из-за того, что у меня есть имя файла содержит новую строку .
Это немного более переносимо, и потому что оно не зависит от find
расширения GNU -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
не.
Здесь описаны некоторые другие решения этой проблемы: Как найти самый последний (самый новый, самый ранний, самый старый) файл в каталоге? - Грег вики
xargs: ls: terminated by signal 13
ошибку как побочный эффект. Я предполагаю, что это SIGPIPE. Я понятия не имею, почему я не получаю подобную ошибку, когда я направляю вывод сортировки в заголовок в моем решении.
head
команда, которая завершает работу после того, как прочитала строку и, таким образом, «разрывает» канал, я думаю. Вы не получаете ошибку, потому sort
что, кажется, не жалуетесь на это, но ls
в другом случае.
xargs
нужно вызывать ls
более одного раза. В этом случае отсортированные выходные данные этих нескольких вызовов в конечном итоге объединяются, когда они должны быть объединены.
ls
его просмотреть и просмотреть самый старый файл, ваше решение, вероятно , превысит ограничение длины командной строки, вызывая ls
его многократный вызов. Вы получите неправильный ответ, но никогда не узнаете.
Следующие команды гарантированно работают с любыми странными именами файлов:
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/[^ ]* //')"
Использование нулевого byte ( \0
) вместо символа перевода строки ( \n
) гарантирует, что вывод find будет по-прежнему понятен в случае, если одно из имен файлов содержит символ перевода строки.
-z
Переключатель делает как - то и 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}'
Команда объяснила:
Запуск это:
~ $ 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
плохо для сценариев, так как его вывод не предназначен для машин, форматирование вывода варьируется в зависимости от реализации. Как вы уже сказали, find
это хорошо для написания сценариев, но также может быть полезно добавить эту информацию, прежде чем рассказывать о ls
решениях.
Пожалуйста, используйте 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
sort -n
.
Кажется, что под «самым старым» большинство людей полагало, что вы имели в виду «самое старое время модификации». Это, вероятно, исправлено в соответствии с самым строгим толкованием «самого старого», но в случае, если вам нужен тот, у которого самое старое время доступа , я бы изменил лучший ответ следующим образом:
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
отображает второй столбец, т.е. имя файла.
find -type f -printf '%T+ %p\n' | sort | head -1