Intereting Posts
Как выполнить удаленную команду и передать ее в локальный файл? Какова цель запуска xterm из обычного терминала Более сжатый способ заблокировать список папок в .htaccess Как установить фоновое изображение для urxvt? Как настроить `less` для печати, начиная с верхней части окна терминала? Где я могу найти сообщения о последней неудачной загрузке Linux? Как удалить идентификатор устройства из введенного вручную драйвера usb-serial Могу ли я получить вчерашнюю статистику с помощью команды sar, но я установил sar сейчас Удаление косой черты / родительских путей из имен файлов внутри CSS и содержимого Javascript Не удалось войти в систему с помощью NFS rootfs Производительность btrfs Почему это, когда я загружаю двоичный файл из Интернета, у него нет установленных разрешений, но когда я использую gcc для создания двоичного файла, он это делает? Неизвестная файловая система после копирования Debian ISO с dd Служба mariadb не запускается после загрузки, CentOS 7 Как иметь один IP-адрес с несколькими серверами

Найти последние версии нескольких файлов в нескольких каталогах

Я пишу приложение, и одним из предварительных условий является просмотр нескольких каталогов и поиск последней версии каждого файла.

У меня был успех с ls и find , чтобы получить последние файлы, но не последнюю версию файла EACH, если эти же файлы находятся в нескольких каталогах. Одно из предостережений заключается в том, что я не обязательно буду знать, какие файлы вызывают, но будет знать имена каталогов.

Пример: DIR1, DIR2 и DIR3 содержат версию FileA и FileB. Мне нужны последние версии FileA и FileB, содержащиеся во всех трех (или более) каталогах.

У кого-нибудь есть идеи?

Вы на правильном пути с выбором инструментов:

  • ls -t – хороший способ сортировать файлы, упорядоченные по времени, чтобы вы могли выбрать последние
  • find – это правильный инструмент для поиска файлов, соответствующих некоторому шаблону в каталогах и подкаталогах

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

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

 find_latest() { pattern=$1 ls -t "$dir1/$pattern" "$dir2/$pattern" "$dir3/$pattern" | head -n 1 } 

Предположим, если у вас есть шаблоны access.log , error.log , x* , то вы можете их перебрать, например:

 for pattern in access.log error.log 'x*'; do latest=$(find_latest 'a*') echo $latest done 

Если вышеприведенное предположение неверно, и файлы могут находиться в подкаталогах $dir1 , $dir2 или $dir3 , тогда вам нужно использовать find , он становится немного сложнее:

 find_latest() { pattern=$1 find "$dir1" "$dir2" "$dir3" -name "$pattern" -print0 | xargs -0 ls -t | head -n 1 } 

Существует небольшая оговорка: если путь содержит символы новой строки, эта функция не будет работать хорошо, потому что head -n 1 будет отрубать часть пути после новой строки. Я скрещиваю пальцы, что у вас нет таких путей 😉

Вы можете сделать это с помощью pax :

 pax -wrtvZs"|.*/||p" ./DIR[123] "$PWD" 

Поэтому я попытаюсь сломать аргумент:

  • -wr – это -wr и правильные, и вместе они означают, что pax должен копировать файлы, а не архивировать. Вы также можете отказаться от копии и просто создать hardlinks вместо этого с -l .

  • -t – это сбрасывает все времена доступа к файлу до состояния, которое они имели до того, как pax прочитал их, чтобы проверить их метаданные.

  • -v – работает в скором времени.

  • -Z – не сравнивает времена модификации исходных файлов до тех пор, пока все возможные замены имен не будут завершены.

    • Именно это (и следующее) делает это настолько легким. Без этого – и, вероятно, проблема, с которой вы DIR1/FILEA другом месте, заключается в том, что DIR1/FILEA и DIR2/FILEA – это разные файлы, даже если они разделяют базовое имя. И поэтому они никогда не сравниваются без этого и …
  • -s – заменить и заменить части имени файла стандартным sed regexp.

    • Здесь я просто уменьшаю все части каждого файла до их FILEA , и поэтому -Z применяется ко всем FILEA s, и только самые новые копируются в "$PWD" .

Для проверки всего этого я использовал следующий тест:

 for d in DIR3 DIR1 DIR2 do cd ~; mkdir -p "$d"; cd "$d" sleep 90; touch FILEB FILEA done; cd ~ 

… который получает тестовый набор. Вот результирующие моды:

 ls -l ./DIR[123]/FILE[AB] -rw-r--r-- 1 mikeserv mikeserv 0 Dec 20 03:28 ./DIR1/FILEA -rw-r--r-- 1 mikeserv mikeserv 0 Dec 20 03:28 ./DIR1/FILEB -rw-r--r-- 1 mikeserv mikeserv 0 Dec 20 03:29 ./DIR2/FILEA -rw-r--r-- 1 mikeserv mikeserv 0 Dec 20 03:29 ./DIR2/FILEB -rw-r--r-- 1 mikeserv mikeserv 0 Dec 20 03:26 ./DIR3/FILEA -rw-r--r-- 1 mikeserv mikeserv 0 Dec 20 03:26 ./DIR3/FILEB 

И так, когда я бегу:

 pax -wrtvZs"|.*/||p" ./DIR[123] "$PWD" ls -l ./FILE[AB] 

… выход …

 ./DIR1/FILEA >> FILEA /home/mikeserv/FILEA ./DIR1/FILEB >> FILEB /home/mikeserv/FILEB ./DIR2/FILEA >> FILEA /home/mikeserv/FILEA ./DIR2/FILEB >> FILEB /home/mikeserv/FILEB ./DIR3/FILEA >> FILEA ./DIR3/FILEB >> FILEB -rw-r--r-- 1 mikeserv mikeserv 0 Dec 20 03:29 ./FILEA -rw-r--r-- 1 mikeserv mikeserv 0 Dec 20 03:29 ./FILEB 

Вы можете видеть, как это происходит. Когда -s

p изменяет имя файла, модификатор p печатает сообщение в stderr . Итак, мы видим, что файлы DIR1 сначала оцениваются и копируются в $PWD , а затем файлы DIR2 получают одинаковое обращение, но файлы DIR3 не копируются, потому что $PWD/FILE[AB] новее, чем они сейчас.