Bagaimana cara mengubah cap waktu folder secara rekursif ke file terbaru?

15

Saya bertanya-tanya apakah ada yang tahu cara mengubah cap waktu folder secara rekursif berdasarkan cap waktu terbaru yang ditemukan dari file dalam folder itu.

Jadi misalnya:

jon @ UbuntuPanther: / media / media / MP3s / Foo Fighters / (1997-05-20) Warna dan Bentuk $ ls -alF
total 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 Foo Fighters - Doll.mp3
-rw-r - r-- 1 jon jon 3151170 2010-04-18 00:51 Foo Fighters - Enough Space.mp3
-rw-r - r-- 1 jon jon 5004289 2010-04-18 00:52 Foo Fighters - Everlong.mp3
-rw-r - r-- 1 jon jon 5803125 2010-04-18 00:51 Foo Fighters - February Stars.mp3
-rw-r - r-- 1 jon jon 4994903 2010-04-18 00:51 Foo Fighters - Hei, Johnny Park! .mp3
-rw-r - r-- 1 jon jon 4649556 2010-04-18 00:52 Foo Fighters - Monkey Wrench.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 - Walking After You.mp3
-rw-r - r-- 1 jon jon 3033660 2010-04-18 00:52 Foo Fighters - Wind Up.mp3

Folder "(1997-05-20) The Color and The Shape" akan memiliki stempel waktu ditetapkan ke 2010-04-18 00:52.

MonkeyWrench32
sumber

Jawaban:

20

Anda dapat menggunakan touch -runtuk menggunakan cap waktu file lain alih-alih waktu saat ini (atau touch --reference=FILE)

Berikut ini dua solusi. Dalam setiap solusi, perintah pertama mengubah waktu modifikasi direktori ke file terbaru langsung di bawahnya, dan perintah kedua melihat seluruh pohon direktori secara rekursif. Ubah ke direktori ( cd '.../(1997-05-20) The Colour and The Shape') sebelum menjalankan salah satu perintah.

Di zsh (hapus Duntuk mengabaikan file dot):

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

Di Linux (atau lebih umum dengan 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-)" .

Namun perhatikan bahwa mereka tidak memiliki karakter baris baru dalam nama file.

Gilles 'SO- berhenti menjadi jahat'
sumber
Perintah berfungsi (saya menggunakan yang Linux) tetapi tidak bekerja secara rekursif. Saya menjalankannya di folder root saya (/ media / media / MP3) dan tidak beruntung dengan sisa direktori artis di sana. Terima kasih atas bantuan Anda sejauh ini.
MonkeyWrench32
@ MonkeyWrench32: Saya menjawab pertanyaan Anda saat saya memahaminya. Apakah Anda ingin menerapkan perintah ke setiap direktori di bawahnya /media/media/MP3s? Kemudian pada zsh: for d in /media/media/MP3s/**/*(/); do touch -r $d/*(Dom[1]) $d; done. Tanpa zsh (tapi sungguh, gunakan zsh, itu hanya lebih sederhana): letakkan perintah dalam skrip dan jalankan find /media/media/MP3s -type d -execdir /path/to/the/script \;.
Gilles 'SANGAT berhenti menjadi jahat'
Kesempurnaan! Anda adalah master zsh! : D
MonkeyWrench32
Jika Anda menggunakan for d in ...bagaimana Anda bisa menyesuaikan yang berikut, jadi itu juga akan berfungsi dengan folder, yang berisi spasi? (itu masih hilang dalam solusi saya)
rubo77
@ rubo77 Saya tidak mengerti apa yang Anda bicarakan. Semua solusi yang saya posting berfungsi pada nama file yang berisi spasi (beberapa di antaranya gagal pada nama file yang mengandung baris baru). Perhatikan bahwa beberapa solusi saya memerlukan zsh, yang tidak memerlukan tanda kutip ganda di sekitar penggantian variabel.
Gilles 'SANGAT berhenti menjadi jahat'
3

Itu bukan "rekursif", itu hanya mengubah semua stempel waktu di folder. Jika itu yang Anda maksud, ada dua langkah.

stat -c '%Y' filenameakan menampilkan stempel waktu dari filename, dan stat -c '%Y %n' *akan menampilkan stempel waktu dan nama file dari setiap file dalam folder, jadi ini akan menemukan nama file dari file yang paling baru dimodifikasi dalam folder saat ini:

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

Setelah dipikir-pikir, ada cara yang lebih mudah untuk mendapatkan stempel waktu tertinggi di folder:

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

Maka Anda ingin mengubah semua file dalam folder untuk memiliki cap waktu yang sama dengan file itu. touch -r foo barakan berubah baruntuk memiliki stempel waktu modifikasi yang sama dengan foo, jadi ini akan mengubah semua file dalam folder untuk memiliki stempel waktu modifikasi yang sama dengan file modifikasi terbaru Anda:

touch -r "$mostrecent" *

Jadi, satu-liner adalah:

touch -r "`ls -t | head -n1`" *
Michael Mrozek
sumber
Mengurai output ls adalah ide yang buruk , meskipun saya akui itu kasus yang menggoda. Masih berisiko jika lsnama file mangles berisi karakter non-ASCII. Jika Anda menginginkan satu kalimat, gunakan zsh :-)
Gilles 'SO- stop being evil'
@ Gilles Memang, tapi saya belum mengalami masalah saat melakukannya; Saya kira karena nama file saya tidak mengandung karakter non-ASCII. Jawaban Anda lebih baik
Michael Mrozek
2

Saya menyatukan pekerjaan dan sekarang:

Ini akan menjadi skrip yang mengubah semua direktori di dalam /tmp/test/ke stempel waktu dari file terbaru di dalam setiap direktori:

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

Anda dapat menambahkan beberapa file pengujian di / tmp seperti ini:

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
rubo77
sumber
1
terima kasih atas hasil edit Anda, ini berhasil! meskipun gema tidak menghapus "lagi, pertama terlihat, seperti itu hilang, tetapi berhasil.
rubo77
2

gunakan saja

find . -exec touch {} \;
Daz
sumber
0

Saya menggunakan skrip ini untuk secara berkala mengatur stempel waktu folder ke konten terbaru. (Ini sangat mirip dengan jawaban 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
mivk
sumber
0

Saya telah mengambil perintah @Gilles zsh dan meningkatkannya agar berfungsi dalam subfolder, tetapi tampaknya zsh sangat tidak efisien untuk bagian ** / * (FDod).

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

Kutipan memungkinkan entri direktori yang berisi spasi dan tab berfungsi dengan benar. FD membuatnya menemukan direktori non-kosong, termasuk yang dimulai dengan., Od membuatnya mencari secara mendalam-pertama , sehingga cap waktu folder induk bisa diperbarui dengan benar.

Saat pengujian, saya perhatikan bahwa kinerja dan jejak memori untuk ** / * (FDod) gila (lebih dari 1,4GB hanya untuk folder 650k), dan ia membaca semuanya sebelum mulai menyentuh folder. Setelah menggantinya dengan find / read itu menjadi lebih cepat, tidak membakar memori, dan mulai hampir langsung.

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

Jika Anda tidak menjalankannya dalam skrip, ganti "$ @" dengan folder tempat Anda ingin menjalankannya.

Aaron Queenan
sumber
-1

Saya tidak terlalu menyukai ketidakjelasan dari perintah shell dan dengan cepat melakukannya dengan python.

Secara rekursif mengatur semua direktori mtimes ke file / direktori mtime yang tidak dikecualikan di dalamnya.

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)
sulit tidur
sumber