Как я изменяю метки времени папки рекурсивно на новейший файл?

Что предложенный Gilles является, вероятно, лучшим ответом, если возможно сделать.

Если бы это не, обходное решение, которое должно работать, должно было бы использовать управление x-мыши для отправки ключей стрелки вверх и вниз каждый раз, когда мышь прокручивается. Я никогда не использовал экраны со шпаклевкой, но я использовал эту установку на шпаклевке в окнах, чтобы смочь просмотреть текстовый файл путем прокрутки с vi или нано. У меня была другая установка профилей, один для 3 прокруток строки и один для 1 прокрутки строки.

15
16.01.2014, 10:07
8 ответов

Можно использовать touch -r использовать метку времени другого файла вместо текущего времени (или touch --reference=FILE)

Вот два решения. В каждом решении первая команда изменяет время изменения каталога к тому сразу из новейшего файла под ним, и вторая команда смотрит на целое дерево каталогов рекурсивно. Изменитесь на каталог (cd '.../(1997-05-20) The Colour and The Shape') прежде, чем выполнить любую из команд.

В zsh (удаляют D проигнорировать точечные файлы):

touch -r *(Dom[1]) .
touch -r **/*(Dom[1]) .

На Linux (или в более общем плане с GNU находят):

touch -r "$(find -mindepth 1 -maxdepth 1 -printf '%T+=%p\n' |
            sort |tail -n 1 | cut -d= -f2-)" .
touch -r "$(find -mindepth 1 -printf '%T+=%p\n' |
            sort |tail -n 1 | cut -d= -f2-)" .

Однако обратите внимание, что те не принимают символов новой строки в именах файлов.

20
27.01.2020, 19:49
  • 1
    работа команд (я использовал Linux), но это не работает рекурсивно. Я выполнил его в своей корневой папке (/media/media/MP3s) и никакой такой удаче с остальной частью каталогов художника туда. Спасибо за Вашу справку до сих пор. –  MonkeyWrench32 03.09.2010, 04:01
  • 2
    @MonkeyWrench32: Я ответил на Ваш вопрос, поскольку я понял это. Вы хотите применить команду к каждому каталогу внизу /media/media/MP3s? Затем в zsh: for d in /media/media/MP3s/**/*(/); do touch -r $d/*(Dom[1]) $d; done. Без zsh (но действительно, используйте zsh, это просто более просто): поместите команду в сценарий и работайте find /media/media/MP3s -type d -execdir /path/to/the/script \;. –  Gilles 'SO- stop being evil' 03.09.2010, 10:10
  • 3
    ! Вы - zsh ведущее устройство! :D –  MonkeyWrench32 03.09.2010, 18:30
  • 4
    Если Вы используете for d in ... как можно адаптировать следующее, таким образом, это будет также работать с папками, которые содержат пробелы? (который все еще отсутствует в моем решении), –  rubo77 16.08.2013, 14:36
  • 5
    @rubo77, я не понимаю то, о чем Вы говорите. Все решения я отправил работу над именами файлов, содержащими пробелы (некоторые из них перестали работать на именах файлов, содержащих новые строки). Обратите внимание, что некоторые мои решения требуют zsh, который не требует двойных кавычек вокруг подстановок переменных. –  Gilles 'SO- stop being evil' 16.08.2013, 15:16

Это не "рекурсивно", это просто изменяет все метки времени в папке. Если это - то, что Вы имеете в виду, существует два шага.

stat -c '%Y' filename произведет метку времени filename, и stat -c '%Y %n' * произведет метку времени и имя файла каждого файла в папке, таким образом, это найдет имя файла последний раз измененного файла в текущей папке:

mostrecent="`stat -c '%Y %n' * | sort -n | tail -n1 | cut -d ' ' -f '2-'`"

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

mostrecent="`ls -t | head -n1`"

Затем Вы хотите изменить все файлы в папке, чтобы иметь ту же метку времени как тот файл. touch -r foo bar изменится bar иметь ту же измененную метку времени как foo, таким образом, это изменит все файлы в папке, чтобы иметь ту же измененную метку времени как Ваш последний раз измененный файл:

touch -r "$mostrecent" *

Так, острота:

touch -r "`ls -t | head -n1`" *
3
27.01.2020, 19:49
  • 1
    Парсинг вывода ls является плохой идеей, хотя я признаю, что это - заманчивый случай. Это все еще опасно если ls имена файлов искажений, содержащие символы неASCII. Если Вы хотите остроты, используйте zsh:-), –  Gilles 'SO- stop being evil' 03.09.2010, 00:42
  • 2
    @Gilles, который Это, но я должен все же столкнуться с проблемой, делающей его; я предполагаю, потому что мои имена файлов не содержат символы неASCII. Ваш ответ лучше, хотя –  Michael Mrozek♦ 03.09.2010, 00:45

Я соединил работу и теперь:

Это было бы сценарием, который изменяет все каталоги внутри /tmp/test/ к метке времени новейшего файла в каждом каталоге:

#!/bin/bash
if [ -z "$1" ] ; then
  echo 'ERROR: Parameter missing. specify the folder!'
  exit
fi
#MODE=tail # change to newest file
MODE=head # change to oldest file
for d in "$1"/*/; do
  echo "running on $d"
  find "$d" -type d -execdir \
    echo touch --reference="$(find "$d" -mindepth 1 -maxdepth 1 -printf '%T+=%p\n' \
                              | sort | "$MODE" -n 1 | cut -d= -f2-)" "$d" \;
    # remove echo to really run it
done

можно добавить некоторые файлы тестирования в/tmp как это:

mkdir /tmp/test
cd /tmp/test
mkdir d1
mkdir d2
touch d1/text1.txt
sleep 1
touch d1/movie1.mov
touch d2/movie2.mov
sleep 1
touch d2/text2.txt
touch notthis.file
2
27.01.2020, 19:49

Мне не очень понравилась неясность shell-команд, и я быстро сделал это в python.

Он рекурсивно устанавливает mtimes всех каталогов на самый новый неисключенный файл/дир mtime внутри.

import os
import sys

EXCLUDE_FILES = ['.DS_Store']
EXCLUDE_DIRS = ['.git', '.hg']

def inheritMTime(path):
    for root, dirs, files in os.walk(path, topdown=False, followlinks=False):
        currentMaxMtime = None
        for subpath in files:
            if subpath in EXCLUDE_FILES:
                print "ignore file", os.path.join(root, subpath)
                continue
            currentMaxMtime = max(currentMaxMtime, os.lstat(os.path.join(root, subpath)).st_mtime)
        for subpath in dirs:
            if subpath in EXCLUDE_DIRS:
                print "ignore dir", os.path.join(root, subpath)
                continue
            currentMaxMtime = max(currentMaxMtime, os.lstat(os.path.join(root, subpath)).st_mtime)
        if currentMaxMtime is not None:
            os.utime(root, (currentMaxMtime, currentMaxMtime))

if __name__ == "__main__":
    for dir in os.listdir(sys.argv[1]):
        if os.path.isdir(dir):
            current = os.path.join(sys.argv[1], dir)
            inheritMTime(current)
-1
27.01.2020, 19:49

просто используйте

find . -exec touch {} \;
3
20.08.2021, 13:40

Я использую этот скрипт для рекурсивной установки меток времени папок для последнего содержимого. (Это очень похоже на ответ Жиля):

#! /bin/bash

# Change mtime of directories to that of latest file (or dir) under it, recursively
# Empty leaf directories, or dirs with only symlinks get the $default_timestamp

default_timestamp='1980-01-01 00:00:00'

dir="$1"

[ -d "$dir" ] || { echo "Usage: $0 directory" >&2; exit 1; }

find "$dir" -depth -type d | while read d; do
    latest=$(find "$d" -mindepth 1 -maxdepth 1 \( -type f -o -type d \) -printf '%T@ %p\n' | sort -n | tail -1 | cut -d' ' -f2-)
    if [ -n "$latest" ]; then
        touch -c -m -r "$latest" "$d" \
            || echo "ERROR setting mtime of '$d' using ref='$f'" >&2
    else
        touch -c -m -d "$default_timestamp" "$d" \
            || echo "ERROR setting mtime of '$d' to default '$default_timestamp'" >&2
    fi
done
0
20.08.2021, 13:40

Я взял команду @Gilles zsh и улучшил ее для работы с подпапками, но кажется, что zsh ужасно неэффективен для части **/ *(FDod ).

# Don't do this
for d in **/*(FDod); do touch -r "$d"/*(Dom[1]) "$d"; done

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

При тестировании я заметил, что производительность и объем памяти для **/ *(FDod )были безумными (более 1,4 ГБ всего для 650 тыс. папок ), и перед запуском он читал все подряд трогать папки. После замены на find/read стал намного быстрее, не жрал память и запустился практически сразу.

#! /usr/bin/env zsh
# Do this instead
find "$@" -depth -type d ! -empty -print0 |while IFS= read -r -d ''; do
    touch -r "$REPLY"/*(Dom[1]) "$REPLY"
done

Если вы не запускаете его в сценарии, замените «$@» папками, из которых вы хотите его запустить.

0
20.08.2021, 13:40

Я хотел обновить mtimeвсех каталогов и файлов в определенном каталоге до текущей метки времени.

Вот что мне помогло-

# recursively update mtime on all directories
find./somedir -type d -exec touch -t $(date +%s) {} + 

# recursively update mtimes on all files
find./somedir -type f -exec touch {} +
1
20.08.2021, 13:40

Теги

Похожие вопросы