Làm cách nào để thay đổi dấu thời gian thư mục theo cách đệ quy thành tệp mới nhất?


15

Tôi đã tự hỏi nếu có ai biết cách thay đổi dấu thời gian của các thư mục theo cách đệ quy dựa trên dấu thời gian mới nhất được tìm thấy của các tệp trong thư mục đó.

Ví dụ:

jon @ UbuntuPanther: / media / media / MP3s / Foo Fighters / (1997-05-20) Màu sắc và hình dạng $ ls -alF
tổng cộng 55220
drwxr-xr-x 2 jon jon 4096 2010-08-30 12:34 ./
drwxr-xr-x 11 jon jon 4096 2010-08-30 12:34 ../
-rw-r - r-- 1 jon jon 1694044 2010-04-18 00:51 Máy bay chiến đấu Foo - Doll.mp3
-rw-r - r-- 1 jon jon 3151170 2010-04-18 00:51 Máy bay chiến đấu Foo - Đủ không gian.mp3
-rw-r - r-- 1 jon jon 5004289 2010-04-18 00:52 Máy bay chiến đấu Foo - Everlong.mp3
-rw-r - r-- 1 jon jon 5803125 2010-04-18 00:51 Foo Fighters - Tháng hai Stars.mp3
-rw-r - r-- 1 jon jon 4994903 2010-04-18 00:51 Foo Fighters - Này, Johnny Park! .mp3
-rw-r - r-- 1 jon jon 4649556 2010-04-18 00:52 Foo Fighters - Monkey Wbler.mp3
-rw-r - r-- 1 jon jon 5216923 2010-04-18 00:51 Foo Fighters - My Hero.mp3
-rw-r - r-- 1 jon jon 4294291 2010-04-18 00:52 Foo Fighters - My Poor Brain.mp3
-rw-r - r-- 1 jon jon 6778011 2010-04-18 00:52 Foo Fighters - New Way Home.mp3
-rw-r - r-- 1 jon jon 2956287 2010-04-18 00:51 Foo Fighters - See You.mp3
-rw-r - r-- 1 jon jon 2730072 2010-04-18 00:51 Foo Fighters - Up in Arms.mp3
-rw-r - r-- 1 jon jon 6086821 2010-04-18 00:51 Foo Fighters - Đi bộ sau You.mp3
-rw-r - r-- 1 jon jon 3033660 2010-04-18 00:52 Máy bay chiến đấu Foo - Wind Up.mp3

Thư mục "(1997-05-20) Màu sắc và hình dạng" sẽ có dấu thời gian được đặt thành 2010-04-18 00:52.

Câu trả lời:


20

Bạn có thể sử dụng touch -rđể sử dụng dấu thời gian của tệp khác thay vì thời gian hiện tại (hoặc touch --reference=FILE)

Đây là hai giải pháp. Trong mỗi giải pháp, lệnh đầu tiên thay đổi thời gian sửa đổi của thư mục thành tệp mới nhất ngay dưới nó và lệnh thứ hai xem xét toàn bộ cây thư mục theo cách đệ quy. Thay đổi thư mục ( cd '.../(1997-05-20) The Colour and The Shape') trước khi chạy bất kỳ lệnh nào.

Trong zsh (xóa Dtệp bỏ qua dấu chấm):

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

Trên Linux (hoặc nói chung hơn với GNU find):

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-)" .

Tuy nhiên lưu ý rằng những cái đó giả sử không có ký tự dòng mới trong tên tệp.


Các lệnh hoạt động (tôi đã sử dụng các Linux) nhưng nó không hoạt động đệ quy. Tôi đã chạy nó trong thư mục gốc (/ media / media / MP3) và không có may mắn như vậy với các thư mục nghệ sĩ còn lại trong đó. Cảm ơn vì sự giúp đỡ của bạn cho đến nay.
MonkeyWbler32

@ MonkeyWbler32: Tôi đã trả lời câu hỏi của bạn khi tôi hiểu nó. Bạn có muốn áp dụng lệnh cho mọi thư mục bên dưới /media/media/MP3skhông? Sau đó trong zsh : for d in /media/media/MP3s/**/*(/); do touch -r $d/*(Dom[1]) $d; done. Không có zsh (nhưng thực sự, sử dụng zsh, nó chỉ đơn giản hơn): đặt lệnh trong một tập lệnh và chạy find /media/media/MP3s -type d -execdir /path/to/the/script \;.
Gilles 'SO- ngừng trở nên xấu xa'

Sự hoàn hảo! Bạn là một bậc thầy zsh! : D
MonkeyWbler32

Nếu bạn sử dụng for d in ...làm thế nào bạn có thể điều chỉnh các mục sau, vì vậy nó cũng sẽ hoạt động với các thư mục chứa khoảng trắng? (vẫn còn thiếu trong giải pháp của tôi)
rubo77

@ rubo77 Tôi không hiểu bạn đang nói gì. Tất cả các giải pháp tôi đã đăng đều hoạt động trên các tên tệp chứa khoảng trắng (một số trong số chúng không thành công với tên tệp chứa dòng mới). Lưu ý rằng một số giải pháp của tôi yêu cầu zsh, không yêu cầu dấu ngoặc kép xung quanh các thay thế khác nhau.
Gilles 'SO- ngừng trở nên xấu xa'

3

Đó không phải là "đệ quy", nó chỉ thay đổi tất cả các dấu thời gian trong một thư mục. Nếu đó là những gì bạn muốn nói, có hai bước.

stat -c '%Y' filenamesẽ xuất dấu thời gian của filenamestat -c '%Y %n' *sẽ xuất dấu thời gian và tên tệp của mỗi tệp trong thư mục, vì vậy điều này sẽ tìm thấy tên tệp của tệp được sửa đổi gần đây nhất trong thư mục hiện tại:

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

Suy nghĩ thứ hai, có một cách dễ dàng hơn để có được dấu thời gian cao nhất trong thư mục:

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

Sau đó, bạn muốn thay đổi tất cả các tệp trong thư mục để có cùng dấu thời gian như tệp đó. touch -r foo barsẽ thay đổi barđể có cùng dấu thời gian được sửa đổi như foo, vì vậy điều này sẽ thay đổi tất cả các tệp trong thư mục để có cùng dấu thời gian được sửa đổi giống như tệp được sửa đổi gần đây nhất của bạn:

touch -r "$mostrecent" *

Vì vậy, lớp lót là:

touch -r "`ls -t | head -n1`" *

Phân tích đầu ra của ls là một ý tưởng tồi , mặc dù tôi thừa nhận đó là một trường hợp hấp dẫn. Sẽ vẫn có rủi ro nếu lstên tệp xoài chứa các ký tự không phải ASCII. Nếu bạn muốn một lớp lót, hãy sử dụng zsh :-)
Gilles 'SO- ngừng trở thành ác quỷ'

@Gilles Đó là, nhưng tôi chưa gặp phải vấn đề gì khi làm điều đó; Tôi cho rằng vì tên tệp của tôi không chứa các ký tự không phải ASCII. Câu trả lời của bạn tốt hơn mặc dù
Michael Mrozek

2

Tôi đặt công việc cùng nhau và bây giờ:

Đây sẽ là một tập lệnh thay đổi tất cả các thư mục bên trong /tmp/test/thành dấu thời gian của tệp mới nhất bên trong mỗi thư mục:

#!/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

bạn có thể thêm một số tệp thử nghiệm trong / tmp như thế này:

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


1
cảm ơn bạn đã chỉnh sửa, nó hoạt động! Mặc dù tiếng vang không loại bỏ "lần nữa, nó trông giống như bị thiếu, nhưng nó hoạt động.
rubo77


0

Tôi sử dụng tập lệnh này để đặt đệ quy dấu thời gian của thư mục thành nội dung mới nhất. (Nó rất giống với câu trả lời của Gilles):

#! /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

Tôi đã sử dụng lệnh zsh @Gilles và tăng cường nó hoạt động trong các thư mục con, nhưng có vẻ như zsh không hiệu quả khủng khiếp cho phần ** / * (FDod).

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

Các trích dẫn cho phép các mục trong thư mục chứa khoảng trắng và tab hoạt động chính xác. FD làm cho nó tìm thấy các thư mục không trống, bao gồm cả các thư mục bắt đầu bằng., Od làm cho nó tìm kiếm theo cách chuyên sâu , để các dấu thời gian của thư mục mẹ được cập nhật đúng.

Khi kiểm tra, tôi nhận thấy rằng hiệu năng và dung lượng bộ nhớ cho ** / * (FDod) là điên rồ (hơn 1,4 GB cho chỉ 650k thư mục) và nó đọc toàn bộ trước khi bắt đầu chạm vào các thư mục. Sau khi thay thế nó bằng find / read, nó trở nên nhanh hơn nhiều, không làm cháy bộ nhớ và bắt đầu gần như ngay lập tức.

#! /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

Nếu bạn không chạy tập lệnh trong tập lệnh, hãy thay thế "$ @" bằng các thư mục bạn muốn chạy tập lệnh đó.


-1

Tôi không thực sự thích sự tối nghĩa của các lệnh shell và nhanh chóng thực hiện nó trong python.

Nó đệ quy đặt tất cả các mtimes thư mục thành tập tin / thư mục không bị loại trừ mới nhất bên trong.

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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.