Как выбрать самый старый файл в папке из каталога

Как выбрать самый старый файл в папке из каталога

У nменя в каталоге есть несколько файлов ../in/. Из этих файлов я хочу обработать самый старый файл и отправить его в ../complete/каталог. Остальные файлы отправляются в каталог ../error/. Может кто-нибудь помочь?

решение1

Чтобы скопировать самый старый файл в ../complete:

cp -v "$(find ../in -maxdepth 1 -type f -printf '%T@ %p\0' | sort -zn | \
  sed -zn '1s/[0-9,\.]\+ //p')" ../complete

Чтобы скопировать все, кроме самых старых, в ../error:

find ../in -maxdepth 1 -type f -printf '%T@ %p\0' | sort -zn | \
  sed -zn '2,$s/[0-9,\.]\+ //p' | xargs -0 cp -vt ../error

Объяснение:

  • find
    • -maxdepth 1спускается только на 1 уровень; поэтому он не будет выполнять рекурсивный поиск в каталоге.
    • -type fтолько соответствующие файлы.
    • -printf '...'пользовательский формат вывода. %T@выдает время последнего изменения файла в виде временной метки, %p— имя файла. Обратите внимание на \0в конце. Файлы печатаются с разделителями в виде нулевого байта, а не с разделителями в виде новой строки, поскольку символ новой строки, вероятно, может быть символом в имени файла, что приведет к сбою команды.
  • sort -znэто прочитает вывод, разделенный нулевым байтом ( -z), и отсортирует его по числовому значению ( -n).
  • sed -znсчитывает вывод, разделенный нулевым байтом.
    • 1будет соответствовать только первой строке (первая команда) и 2,$всем остальным (вторая команда)
    • s/[0-9,\.]\+ //pудалит начальную временную метку из выходных данных.
  • Только из второй команды: xargs -0 cp -vt ../errorобрабатывает выходные данные, разделенные нулевым байтом ( -0), и вызывает cp -vt ../errorвсе входные данные, которые копируют файлы.

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

$ ls -lt ../in/
total 0
-rw-r--r-- 1 user user 0 Jun 24 08:18 file2
-rw-r--r-- 1 user user 0 Jun 24 08:18 file3
-rw-r--r-- 1 user user 0 Jun 24 08:18 file4
-rw-r--r-- 1 user user 0 Jun 24 08:18 file5
-rw-r--r-- 1 user user 0 Jun 24 08:17 file_oldest
$ cp -v "$(...)" ../complete
'../in/file_oldest' -> '../complete/file_oldest'
$
$ find ... | xargs ... ../error
'../in/file2' -> '../error/file2'
'../in/file3' -> '../error/file3'
'../in/file4' -> '../error/file4'
'../in/file5' -> '../error/file5'

решение2

Чтобы найти самый старый файл и переместить его в нужный каталог, используйте:

# cd to ../in/

$ ls -lt | grep -v '^d' | tail -1 | awk '{print $NF}' | xargs -I '{}' mv '{}' ../complete/

Теперь, когда ваш самый старый файл перемещен, вы можете переместить все файлы в../error/

$ mv -- * ../error/

Последующее необходимо, если у вас есть имена файлов/каталогов, начинающиеся --с .mv-

решение3

Опираясь наОтвет Рахула:

$ ls -ltr | grep -v '^d' | awk 'NR==2 {print $NF; exit}' | xargs -I '{}' mv -- '{}' ../complete/

Примечания:

  • Вы говорите, что хотите что-то сделать с «самым старым файлом». Все ответы предполагают, что вы имеете в виду наименее недавно измененный. Если вы имеете в виду наименее недавноизмененный, так и скажите; ответы будут немного отличаться. Если вы имеете в виду наименее недавносозданный, то, что вы хотите, практически невозможно в Unix.
  • ls -ltls -ltr( то , что использовал Рахул) выводит список текущего каталога в длинном формате в порядке даты/времени изменения, начиная с самого нового и заканчивая самым старым.  рнаоборот: сначала самые старые, а последние самые новые.
  • Если у вас есть файлы, имена которых начинаются с точки (.), добавьте Aпараметр к ls; например, ls -ltrA. (Порядок параметров не имеет значения; вы можете использовать ls -ltAr, ls -lAtr, или даже ls -ltr -A, если хотите.)
  • Я солгал. Длинный lsсписок каталога всегда имеет totalстроку в начале. В ls -ltr, самая старая запись находится навторойлиния.
  • grep -v '^d'отфильтровывает каталоги (если таковые имеются).
  • awk 'NR==2 { print $NF; exit }' печатает последнее поле (имя файла*) из второй строки (самый старый файл) и затем выходит.

    • Это на один процесс меньше, чем tail -1 | awk '{print $NF}'.
    • Это может работать быстрее, поскольку при awkвыходе lsможет также выйти и вам не придется создавать список для всего каталога.
    • Вы можете устранить это, grepвыполнив следующие действия:

      ls -ltr | awk '! /^d/ { count++ } count==2 { print $NF; exit }'
      

      но я бы не советовал. Слишком сложные скрипты трудно поддерживать.

  • После--mv в xargsкоманденеобходимо, если у вас есть имена файлов, начинающиеся с-.
  • Вам на самом деле не нужно xargs. Вы можете упростить команду выше до

    $ mv -- $(ls -ltr | grep -v '^d' | awk 'NR==2 { print $NF; exit }') ../complete/
    

________
* Как и в ответе Рахула, это не сработает, если имя файла содержит пробелы или табуляции, и еще хуже, если оно содержит переводы строк.

Если у вас есть файлы, имена которых начинаются с точки (.), сделайте shopt -s dotglobперед выполнением

$ mv -- * ../error/

Связанный контент