Рекурсивно соприкасается с последней измененной датой-временем каталогов с той же датой-временем последнего измененного файла внутри
Ранее я бегал dos2unix
на каждом *.php
файл на моем сервере рекурсивно с этой командой:
find . -name '*.php' -type f -exec dos2unix --keepdate {} +
Все файлы обработаны dos2unix
у него было последнее изменение даты и времени, но в родительском каталоге, содержащем такие файлы, время последнего изменения даты и времени обновлялось до того времени, когда я выполнил команду.
Как мне с помощью одной строки рекурсивно дотронуться до каталогов, установив дату последнего изменения каталогов равной дате и времени последнего измененного файла в каталоге?
Из этого:
dir_a/ 2013-05-13 14:05
abc.php 2012-09-01 12:34
def.php 2012-09-15 23:45
dir_b/ 2013-05-13 14:05
uvw.php 2012-10-01 01:23
xyz.php 2012-10-08 09:10
К этому:
dir_a/ 2012-09-15 23:45
abc.php 2012-09-01 12:34
def.php 2012-09-15 23:45
dir_b/ 2012-10-08 09:10
uvw.php 2012-10-01 01:23
xyz.php 2012-10-08 09:10
Сервер работает на CentOS 5.6.
2 ответа
Может быть, что-то вроде этого:
find . -type d -print0 | while read -r -d '' dir; do file="$(find "$dir" -maxdepth 1 -type f -printf '%T+ %p\n' | sort -r | head -1 | cut -d' ' -f2-)";if [ -n "$file" ]; then touch "$dir" -mr "$file"; fi; done
Объяснение:
Чтобы передать дату модификации из одного файла в другой, нам нужно выполнить:
touch file1 -mr file2
Сначала мы должны найти подкаталоги:
find . -type d -print0 | while read -r -d '' dir; do echo "$dir"; done
В этом случае -exec
вариант будет слишком сложным, поэтому я использую подход пока читаю. Вы должны убедиться, что поток от find
с NUL
в качестве разделителя записей, и сказать read
разделить на это (-d ''
).
Для поиска файлов с последней датой модификации я могу использовать:
find ./ -maxdepth 1 -type f -printf '%T+ %p\n' | sort -r | head -1 | cut -d' ' -f2-
Сочетая это:
find . -mindepth 1 -type d -print0 | while read -r -d '' dir; do file="$(find "$dir" -maxdepth 1 -type f -printf '%T+ %p\n' | sort -r | head -1 | cut -d' ' -f2-)";echo "$dir <- $file"; done
Наконец, добавление прикосновения:
find . -mindepth 1 -type d -print0 | while read -r -d '' dir; do file="$(find "$dir" -maxdepth 1 -type f -printf '%T+ %p\n' | sort -r | head -1 | cut -d' ' -f2-)";touch "$dir" -mr "$file"; done
я использую -mindepth
здесь, потому что я запустил эту команду из каталога, содержащего dir_a, у которого нет файла для чтения даты. Чтобы устранить эту проблему, я могу использовать if-else, чтобы убедиться, что я не пытаюсь прочитать время из несуществующего файла:
find . -type d -print0 | while read -r -d '' dir; do file="$(find "$dir" -maxdepth 1 -type f -printf '%T+ %p\n' | sort -r | head -1 | cut -d' ' -f2-)";if [ -n "$file" ]; then touch "$dir" -mr "$file"; fi; done
Это должно сделать это:
find -mindepth 1 -type d -print0 | while IFS= read -r -d '' dir; do
time=$(
find "$dir" -mindepth 1 -maxdepth 1 -type f -exec stat -c %Y {} \; |
sort -nk2 | tail -n 1
); touch -d @$time "$dir";
done
ОБЪЯСНЕНИЕ:
find -mindepth 1 -type d | while IFS= read -r -d '' dir; do
: перебрать все каталоги, кроме текущего (-mindepth 1
). Используяwhile
цикл сIFS=
и-r
Флаг должен убедиться, что команда работает с именами каталогов, которые содержат пробелы или новые строки (\n
) или другие странные персонажи.-d ''
устанавливает разделитель на нулевой символ, чтобы он мог работать с Find-print0
вариант.find $dir -mindepth 1 -maxdepth 1 -type f -exec stat --printf="%Y\n" {} \;
: Найти все файлы каждого каталога$dir
и бегиstat
который печатает дату их модификации в секундах с начала эпохи.sort -nk2 | tail -n 1
Это просто сортирует даты и сохраняет самые новые. Последние две части вместе дают время модификации самого нового файла, который сохраняется в переменной$time
,touch -d @$time $dir
: здесь мы используемtouch
Команда для установки времени модификации каждого каталога.@
есть что сказатьtouch
что мы даем время в секундах с начала эпохи, это стандартная функция ядра GNU coreutils.