Unix / Linux найти и отсортировать по дате изменения

138

Как я могу сделать простой, findкоторый бы упорядочил результаты по самым последним модифицированным?

Вот текущий ток, который findя использую (я делаю экранирование оболочки в PHP, так что это аргумент для переменных):

find '$dir' -name '$str'\* -print | head -10

Как я мог иметь этот порядок поиска по самым последним модифицированным? (Обратите внимание, я не хочу, чтобы он сортировал «после» поиска, а скорее находил результаты на основе того, что было недавно изменено.)

Питер Мортенсен
источник
github.com/shadkam/recentmost будет делать то, что нужно - но нужно его построить
user3392225

Ответы:

153

Использовать это:

find . -printf "%T@ %Tc %p\n" | sort -n

printfаргументы от man find:

  • %Tk: Время последнего изменения файла в формате, указанном k.

  • @: секунды с 1 января 1970 года, 00:00 по Гринвичу, с дробной частью.

  • c: дата и время локали (сб. 04 ноября 12:02:33 EST 1989).

  • %p: Имя файла.

user195696
источник
5
+1 Очень полезно, первый ответ на этот вопрос я нашел с выводом удобочитаемой / полезной даты
Джейк N
самый надежный (и очень простой), так как время предоставляется численно последовательным (поэтому всегда правильно сортируемым), спасибо!
Водолей Сила
1
У меня есть этот псевдоним для поиска последних файлов в моем ~/.zshrc: fr () { find ./ -iname "*"$@"*" -printf "%T@ %Td-%Tb-%TY %Tk:%TM %p\n" | sort -n | cut -d " " -f 2- | grep -i "$@" ; }он рекурсивно находит все файлы, содержащие шаблон первого аргумента, переданного команде ( fr <pattern>), и сортирует их по последнему последнему.
joelostblom
Это здорово !!! Чтобы использовать с символическими ссылками, используйтеfind -L ...
Варун Чандак
1
Возможно, вы захотите использовать, ssedчтобы избавиться от дробной части секунд, и все еще используйте ISO8601, как показало @PeterMortensen:find . -type f -printf "%TY-%Tm-%TdT%TT %p\n" | sort -r | ssed -R 's/^([^.]+)\.\d+ (.*)$/\1 \2/'
Людовик Куты
83

Самый простой способ - использовать zsh благодаря его квалификаторам glob .

print -lr -- $dir/**/$str*(om[1,10])

Если у вас есть GNU find, заставьте его распечатать время изменения файла и отсортировать по нему.

find -type f -printf '%T@ %p\0' |
sort -zk 1nr |
sed -z 's/^[^ ]* //' | tr '\0' '\n' | head -n 10

Если у вас есть GNU find, но нет других утилит GNU, используйте символы новой строки вместо разделителей; вы потеряете поддержку имен файлов, содержащих переводы строк.

find -type f -printf '%T@ %p\n' |
sort -k 1nr |
sed 's/^[^ ]* //' | head -n 10

Если у вас есть Perl (здесь я предполагаю, что в именах файлов нет новых строк):

find . -type f -print |
perl -l -ne '
    $_{$_} = -M;  # store file age (mtime - now)
    END {
        $,="\n";
        @sorted = sort {$_{$a} <=> $_{$b}} keys %_;  # sort by increasing age
        print @sorted[0..9];
    }'

Если у вас есть Python (также предполагается, что в именах файлов нет перевода строки):

find . -type f -print |
python -c 'import os, sys; times = {}
for f in sys.stdin.readlines(): f = f[0:-1]; times[f] = os.stat(f).st_mtime
for f in (sorted(times.iterkeys(), key=lambda f:times[f], reverse=True))[:10]: print f'

Вероятно, есть способ сделать то же самое в PHP, но я этого не знаю.

Если вы хотите работать только с инструментами POSIX, это довольно сложно; см. Как вывести список файлов, отсортированных по дате изменения рекурсивно (команда stat недоступна!) (повторная установка первых 10 - самая простая часть).

жилль
источник
Я думаю, что findверсия показывает самые старые файлы, и вам нужно добавить эту -rопцию sort.
Квентин Праде
Мой sed говорит, что у него нет опции -z.
Кеф Шектер
@KefSchecter Тогда используйте новые строки в качестве разделителей, но вы потеряете поддержку новых строк в именах файлов.
Жиль
Выше для python2. Если у вас есть только python3, некоторые небольшие изменения: python3 -c 'import os, sys; времена = {} для f в sys.stdin.readlines (): f = f [0: -1]; times [f] = os.stat (f) .st_mtime для f in (отсортировано (times.keys (), ключ = лямбда f: times [f], reverse = True)) [: 10]: print (f); '
Нил МакГилл
40

Вам не нужен PHP или Python, просто ls :

man ls:
-t     sort by modification time
-r,    reverse order while sorting (--reverse )
-1     list one file per line

find /wherever/your/files/hide -type f -exec ls -1rt "{}" +;

Если команда * завершается со статусом ошибки (т. Е. Список аргументов слишком длинный ), вы можете выполнить итерацию с помощью команды find. Перефразировано из: Максимальная длина аргументов для нового процесса

  • find . -print0|xargs -0 command (оптимизирует скорость, если find не реализует "-exec +", но знает "-print0")
  • find . -print|xargs command (если в аргументах нет пробелов)

Если основная часть аргументов состоит из длинных, абсолютных или относительных путей, попробуйте переместить ваши действия в каталог. cd /directory/with/long/path; command *И еще одно быстрое решение может состоять в том, чтобы соответствовать меньшему количеству аргументов:command [a-e]*; command [f-m]*; ...

Ярослав Рахматуллин
источник
1
Если файлов много, это не удастся, так как «lus слишком длинный список аргументов».
Occulus
1
Это правда, но я считаю, что вопрос был «как мне сделать простую находку ...»
Ярослав Рахматуллин
2
ls не заключает в кавычки имена файлов так, как может понять xargs (опция -0 отсутствует, а различные стили цитирования неадекватны)
Тобу
10

Вам нужно только LS

Вы можете сделать, find /wherever/your/files/hide -type f -exec ls -1rt "{}" +;как указано выше,

или же

ls -1rt `find /wherever/your/file/hides -type f`
skippy1910
источник
2
Если файлов много, это не удастся, так как «lus слишком длинный список аргументов». Может быть, recook использовать Xargs?
Occulus
2
Но если xargsзвонит lsнесколько раз, сортировка будет нарушена.
Аарон Д. Мараско
Это не работает для файлов с пробелами в их именах. Любой совет?
user74094
Просто наткнулся на этот ответ, и это было именно то, что мне нужно в подобной ситуации. Вопрос: что делает +;в конце? Кажется, что дает тот же результат без, ;однако он не работает без +?
RocketNuts
Это так же, как и другой ответ, опубликованный за 8 месяцев до этого, за исключением части об использовании "ls -1rt` find… `", которая не работает
Clément
7

Расширение ответа пользователя 195696 :

find . -type f -printf "%T@\t%Tc %6k KiB %p\n" | sort -n | cut -f 2-

Для каждого файла сначала выводится числовая временная метка (для сортировки с последующим табулированием \t), затем удобочитаемая временная метка, затем размер файла (к сожалению, findэто -printfневозможно в мегабайтах, только в кибибайтах), затем имя файла с относительным дорожка.

Затем sort -nсортирует его по первому числовому полю.

Затем cutизбавляется от того первого числового поля, которое не представляет интереса для пользователя. (Печатает второе поле вперед.) Разделителем полей по умолчанию является \tили табуляция.

Пример вывода:

Thu 06 Feb 2014 04:49:14 PM EST     64 KiB ./057_h2_f7_10/h2_f7_10.class
Fri 07 Feb 2014 02:08:30 AM EST 7962976 KiB ./056_h2_f7_400/h2__rh_4e-4.mph
Fri 07 Feb 2014 02:23:24 AM EST 7962976 KiB ./056_h2_f7_400/h2_f7_400_out_Model.mph
Fri 07 Feb 2014 02:23:24 AM EST      0 KiB ./056_h2_f7_400/h2_f7_400_out.mph.status
Fri 07 Feb 2014 02:23:24 AM EST     64 KiB ./056_h2_f7_400/1579678.out
Fri 07 Feb 2014 03:47:31 AM EST 8132224 KiB ./057_h2_f7_10/h2__rh_1e-5.mph
Fri 07 Feb 2014 04:00:49 AM EST 8132224 KiB ./057_h2_f7_10/h2_f7_10_out_Model.mph
Fri 07 Feb 2014 04:00:49 AM EST      0 KiB ./057_h2_f7_10/h2_f7_10_out.mph.status
Fri 07 Feb 2014 04:00:49 AM EST     64 KiB ./057_h2_f7_10/1579679.out
Fri 07 Feb 2014 09:47:18 AM EST   9280 KiB ./056_h2_f7_400/h2__rh_4e-4.mat
Fri 07 Feb 2014 10:51:23 AM EST   9728 KiB ./018_bidomain/h2_plain__rh_1e-5.mat
Fri 07 Feb 2014 10:58:33 AM EST   9568 KiB ./057_h2_f7_10/h2__rh_1e-5.mat
Fri 07 Feb 2014 05:05:38 PM EST     64 KiB ./058_h2_f7_stationary/h2_f7_stationary.java
Fri 07 Feb 2014 06:06:29 PM EST     32 KiB ./058_h2_f7_stationary/slurm.slurm
Sat 08 Feb 2014 03:42:07 AM EST      0 KiB ./058_h2_f7_stationary/1581061.err
Sat 08 Feb 2014 03:42:14 AM EST     64 KiB ./058_h2_f7_stationary/h2_f7_stationary.class
Sat 08 Feb 2014 03:58:28 AM EST  70016 KiB ./058_h2_f7_stationary/h2s__rh_1e-5.mph
Sat 08 Feb 2014 04:12:40 AM EST  70304 KiB ./058_h2_f7_stationary/h2s__rh_4e-4.mph
Sat 08 Feb 2014 04:12:53 AM EST  70304 KiB ./058_h2_f7_stationary/h2_f7_stationary_out_Model.mph
Sat 08 Feb 2014 04:12:53 AM EST      0 KiB ./058_h2_f7_stationary/h2_f7_stationary_out.mph.status
Sat 08 Feb 2014 04:12:53 AM EST     32 KiB ./058_h2_f7_stationary/1581061.out
Mon 10 Feb 2014 11:40:54 AM EST    224 KiB ./058_h2_f7_stationary/h2s__rh_4e-4.mat
Mon 10 Feb 2014 11:42:32 AM EST    224 KiB ./058_h2_f7_stationary/h2s__rh_1e-5.mat
Mon 10 Feb 2014 11:50:08 AM EST     32 KiB ./plot_grid.m

Я намеренно сделал поле размера файла 6 символов, потому что, если сделать его длиннее, становится трудно визуально различать, насколько большие файлы. Таким образом, файлы размером больше 1e6 КиБ выделяются: на 1 символ - 1-9 ГБ, на 2 символа - 10-99 ГБ и т. Д.


Изменить: вот еще одна версия (так как происходит find . -printf "%Tc"сбой на MinGW / MSYS):

find . -type f -printf "%T@\t%p\n" | sort -n | cut -f 2- | xargs -I{} ls -Glath --si {}

Давать вывод как:

-rw-r--r-- 1 es 23K Jul 10  2010 ./laptop_0000071.jpg
-rw-r--r-- 1 es 43M Jul 29 19:19 ./work.xcf
-rw-r--r-- 1 es 87K Jul 29 20:11 ./patent_lamps/US Patent 274427 Maxim Lamp Holder.jpg
-rw-r--r-- 1 es 151K Jul 29 20:12 ./patent_lamps/Edison screw-in socket.png
-rw-r--r-- 1 es 50K Jul 29 20:13 ./patent_lamps/1157 Lamp.jpg
-rw-r--r-- 1 es 38K Jul 29 20:14 ./patent_lamps/US06919684-20050719-D00001.png

Где:

  • -I{}вызывает вхождение {}аргумента в качестве аргумента, и теперь новые строки являются разделителями аргументов (обратите внимание на пробелы в именах файлов выше).

  • ls -G подавляет печать имени группы (пустая трата места).

  • ls -h --siпроизводит удобочитаемые размеры файлов (более правильно с --si).

  • ls -t сортирует по времени, что здесь не имеет значения, но это то, что я обычно использую.

Евгений Сергеев
источник
1
Примечание: для сортировки файлов размером вместо этого, просто заменить свой T@путь sв любом из указанных выше команд.
Евгений Сергеев
3

Вариант OS X ответа @ user195696:

  1. С отметкой времени:

    find . -type f -exec stat -f "%Sm %N" -t "%Y%y%m%d%H%M" {} \; | sort -r
    
  2. Без отметки времени:

    find . -type f -exec stat -f "%Sm %N" -t "%Y%y%m%d%H%M" {} \; | sort -r | awk -F' ' '{ print substr($0, length($1) + 2) }'
    
user9399
источник
2

Я обнаружил, что это делает работу на Mac OS X (и достаточно общей, чтобы работать на других Unixen):

find . -type f -ls | awk '{print $(NF-3), $(NF-2), $(NF-1), $NF}' | sort
Брайан Петти
источник
2
К сожалению, это печатает локализованные названия месяцев на моей хорватской установке, делая сортировку некорректной.
Иван Вучица
Ответ пользователя 195696 работает для хорватской настройки (и других).
Питер Мортенсен
1

Если ваш findвыбор очень прост, вы можете обойтись без него и просто использовать ls:

ls -1 *.cc # -r -t optional
DJC
источник
1

Пытаться:

find '$dir' -name '$str'\* -print | xargs ls -tl | head -10

Но также полезно фильтровать данные по -mmin/ -mtimeи -type.

Питер Мортенсен
источник
1

Использование:

find . -type f -mtime 0 -printf "[%TD %TI:%TM%Tp] %s %p\n" | sort -n | awk '{
    hum[1024**4]="TB"; hum[1024**3]="GB"; hum[1024**2]="MB"; hum[1024]="KB"; hum[0]="B";
    for (x=1024**4; x>=1024; x/=1024){
    if ($3>=x) { printf $1" "$2"\t%7.2f %s\t%s\n",$3/x,hum[x],$4;break }
    }}';

Эта команда отсортирует файлы по дате изменения.

И отображать как:

[12/05/13 03:10PM] 1.75 MB ./file.text
[12/06/13 11:52PM] 2.90 MB ./file2.mp4
[12/07/13 04:11PM] 4.88 MB ./file3.mp4
[12/07/13 09:17PM] 4.74 MB ./test.apk
Акаша
источник
Я улучшил этот скрипт для обработки пробелов в именах файлов, см. Superuser.com/a/777007/134532
янв
1

У меня есть простое решение, которое работает как для FreeBSD (OS X), так и для Linux:

find . -type f -exec ls -t {} +
Алекс Щур
источник
Это работает отлично - должен быть правильный ответ или хотя бы более высокий рейтинг!
digitaltoast
0

Я не думаю, что findесть какие-либо варианты изменить порядок вывода. -mtimeи -mminпозволит вам ограничить результаты файлами, которые были изменены в течение определенного промежутка времени, но выходные данные не будут отсортированы - вам придется делать это самостоятельно. В GNU findесть -printfопция, которая, помимо прочего, позволит вам печатать время модификации каждого найденного файла (строки формата %tили %Tk); это может помочь вам отсортировать findрезультаты так, как вы хотите.

Джим Льюис
источник
0

Я улучшил ответ Akashs, сделав скрипт, корректно обрабатывающий пробелы в именах файлов:

find . -type f -mtime 0 -printf ";[%TD %TI:%TM%Tp];%s;%p\n" | sort -n | awk -F ";" '{
    hum[1024**4]="TB"; hum[1024**3]="GB"; hum[1024**2]="MB"; hum[1024]="KB"; hum[0]="B";
    for (x=1024**4; x>=1024; x/=1024){
    if ($3>=x) { printf $1" "$2"\t%7.2f %s\t%s\n",$3/x,hum[x],$4;break }
    }}';
январь
источник
0

Если вы хотите заказать все файлы PNG по времени в $PWD:

Этот простой однострочник дает всю гибкость регулярного выражения снова findи снова ls.

find $PWD -name "*.png" -print0 | xargs -0 ls -laht | less
Джон Смит
источник
0

Вы можете использовать statв BSD и Linux (не в POSIX) следующим образом:

$ stat -f "%m%t%N" /[the dir]/* | sort -rn | cut -f2-

Если вы хотите ограничить количество:

$ stat -f "%m%t%N" /[the dir]/* | sort -rn | head -[the number] | cut -f2-
drewk
источник
0

Существует чистый и надежный способ sort | headпо дате:

Использование ls -lдля красивой печати

find . ! -type d -printf "%T@ %p\0" |
    sort -zrn |
    head -zn 10 |
    sed -z 's/^[0-9.]\+ //' |
    xargs -0 ls -lt

В качестве функции :

findByDate() {
    local humansize=''
    [ "$1" = "-h" ] && humansize='h' && shift
    find . ${2:-! -type d} -printf "%T@ %p\0" |
        sort -zrn |
        head -zn ${1:--0} |
        sed -z 's/^[0-9.]\+ //' |
        xargs -0 ls -dlt${humansize}
}

Это может быть выполнено с одним или двумя аргументами или даже без:

Usage: findByDate [-h] [lines] [find options]

Образец:

findByDate

Перечислите все не каталоги, отсортированные по дате. Nota:

Даже в большом дереве файловой системы, как и в случае xargs уже отсортированного списка, порядок файлов остается правильным, даже если его lsнужно запускать много раз.

findByDate -h 12

Перечислите еще 12 последних не-каталогов, отсортированных по дате, с размером, напечатанным в удобочитаемой форме.

findByDate 42 '-type l'

Перечислим еще 42 последние ссылки

findByDate -0 '( -type l -o -type b -o -type s -o -type c )'

Будут перечислены все символические ссылки, блочные устройства, сокеты и символы устройств, отсортированные по дате.

Инвертирующий порядок

Замена headна tailи изменить переключатель sortи ls:

findByDate() {
    local humansize=''
    [ "$1" = "-h" ] && humansize='h' && shift
    find . ${2:-! -type d} -printf "%T@ %p\0" |
        sort -zn |
        tail -zn ${1:-+0} |
        sed -z 's/^[0-9.]\+ //' |
        xargs -0 ls -dltr${humansize}
}

Та же функция, то же использование:

Usage: findByDate [-h] [lines] [find options]
Ф. Хаури
источник
-1

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

 find FIND_ROOT -maxdepth 1 -type f -printf "%T@ %p\n" | sort -nr | head -10 | cut -d ' ' -f 2

Где
-printf "% T @% p \ n" для предоставления критериев сортировки (дата),
'sort -nr' для сортировки по дате,
head -10 для перечисления 10 лучших результатов,
cut -d '' -f 2 для вырезания ведущие отметки времени на каждой строке.

Дэвид Юнг
источник
cut -d ' ' -f 2сломается, если имена файлов содержат пробелы.
Ф. Хаури
-3

У меня есть простое решение.

После того, cdкак в каталог, используйте

find . -iname "*" -ls

петь
источник
1
Это не сортирует по дате изменения.
DavidPostill