ฉันจะเปลี่ยนการประทับเวลาของโฟลเดอร์เป็นไฟล์ใหม่ล่าสุดซ้ำได้อย่างไร


15

ฉันสงสัยว่าถ้าใครรู้วิธีเปลี่ยนการประทับเวลาของโฟลเดอร์ซ้ำโดยอ้างอิงจากการประทับเวลาล่าสุดที่พบของไฟล์ในโฟลเดอร์นั้น

ตัวอย่างเช่น:

jon @ UbuntuPanther: / media / media / MP3s / Foo Fighters / (1997-05-20) The Color and The Shape $ ls -alF
รวม 55220
drwxr-xr-x 2 จอนจอน 4096 2010-08-30 12:34 ./
drwxr-xr-x 11 จอนจอน 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 - เฮ้, จอห์นนี่พาร์ค! .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 - ทางบ้านใหม่. 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 - อัพในอ้อมแขน. 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 - ไขลาน. mp3

โฟลเดอร์ "(1997-05-20) The Color and The Shape" จะมีการตั้งเวลาบันทึกเป็น 2010-04-18 00:52

คำตอบ:


20

คุณสามารถใช้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-)" .

อย่างไรก็ตามโปรดทราบว่าอักขระเหล่านั้นไม่มีอักขระบรรทัดใหม่ในชื่อไฟล์


คำสั่งใช้งานได้ (ฉันใช้ลีนุกซ์) แต่มันไม่ทำงานซ้ำ ๆ ฉันวิ่งไปที่โฟลเดอร์ราก (/ media / media / MP3s) และไม่มีโชคเช่นนี้กับไดเรกทอรีศิลปินอื่น ๆ ขอบคุณสำหรับความช่วยเหลือของคุณ
MonkeyWrench32

@ MonkeyWrench32: ฉันตอบคำถามของคุณเมื่อฉันเข้าใจ คุณต้องการใช้คำสั่งกับทุกไดเรกทอรีภายใต้/media/media/MP3sหรือไม่ จากนั้นใน for d in /media/media/MP3s/**/*(/); do touch -r $d/*(Dom[1]) $d; donezsh: โดยไม่ต้อง zsh ( แต่จริงๆใช้ zsh ก็เพียงง่าย): find /media/media/MP3s -type d -execdir /path/to/the/script \;ใส่คำสั่งในสคริปต์และเรียกใช้
Gilles 'หยุดชั่วร้าย'

ความสมบูรณ์แบบ! คุณเป็น zsh master! : D
MonkeyWrench32

หากคุณใช้for d in ...วิธีที่คุณสามารถปรับเปลี่ยนสิ่งต่อไปนี้ดังนั้นมันจะทำงานกับโฟลเดอร์ที่มีช่องว่างได้หรือไม่ (ที่ยังขาดหายไปในโซลูชันของฉัน)
rubo77

@ rubo77 ฉันไม่เข้าใจสิ่งที่คุณกำลังพูดถึง โซลูชันทั้งหมดที่ฉันโพสต์ทำงานกับชื่อไฟล์ที่มีช่องว่าง (บางส่วนของพวกเขาล้มเหลวในชื่อไฟล์ที่มีการขึ้นบรรทัดใหม่) โปรดทราบว่าโซลูชันบางตัวของฉันจำเป็นต้องใช้ zsh ซึ่งไม่จำเป็นต้องมีเครื่องหมายคำพูดคู่ล้อมรอบการแทนที่ตัวแปร
Gilles 'หยุดความชั่วร้าย' ใน

3

นั่นไม่ใช่ "ซ้ำ" มันแค่เปลี่ยนเวลาทั้งหมดในโฟลเดอร์ ถ้านั่นคือสิ่งที่คุณหมายถึงมีสองขั้นตอน

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เป็น timestamp ที่แก้ไขเช่นเดียวกันfooดังนั้นสิ่งนี้จะเปลี่ยนไฟล์ทั้งหมดในโฟลเดอร์เพื่อให้มีการประทับเวลาที่แก้ไขเช่นเดียวกับไฟล์ล่าสุดที่คุณแก้ไข:

touch -r "$mostrecent" *

ดังนั้นซับเดียวคือ:

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

การแยกวิเคราะห์ผลลัพธ์ของ ls เป็นความคิดที่ไม่ดีแม้ว่าฉันยอมรับว่าเป็นกรณีที่ดึงดูด ยังคงมีความเสี่ยงหากlsชื่อไฟล์ mangles มีอักขระที่ไม่ใช่ ASCII หากคุณต้องการ One-liners ให้ใช้ zsh :-)
Gilles 'SO- หยุดความชั่วร้าย'

@Gilles มันเป็น แต่ฉันยังไม่พบปัญหาในการทำมัน; ฉันคิดว่าเพราะชื่อไฟล์ของฉันไม่มีอักขระที่ไม่ใช่ ASCII คำตอบของคุณดีกว่าแม้ว่า
Michael Mrozek

2

ฉันรวบรวมผลงานเข้าด้วยกันและตอนนี้:

นี่จะเป็นสคริปต์ที่เปลี่ยนไดเรกทอรีทั้งหมดภายใน /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


1
ขอบคุณสำหรับการแก้ไขมันใช้งานได้! แม้ว่าเสียงสะท้อนจะลบ"อีกครั้ง แต่ก่อนจะดูเหมือนว่าหายไป แต่ใช้งานได้
rubo77


0

ฉันใช้สคริปต์นี้เพื่อตั้งค่าการประทับเวลาโฟลเดอร์ซ้ำเป็นเนื้อหาล่าสุด (มันคล้ายกับคำตอบของ 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

ฉันใช้คำสั่ง @Gilles zsh และปรับปรุงให้ทำงานในโฟลเดอร์ย่อย แต่ดูเหมือนว่า zsh ไม่มีประสิทธิภาพมากสำหรับส่วน ** / * (FDod)

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

เครื่องหมายคำพูดอนุญาตให้รายการไดเรกทอรีที่มีช่องว่างและแท็บทำงานได้อย่างถูกต้อง FD ทำให้ค้นหาไดเรกทอรีที่ไม่ว่างเปล่ารวมถึงไดเรกทอรีที่ขึ้นต้นด้วย od ทำให้ค้นหาในเชิงลึกก่อนเพื่อให้การประทับเวลาของโฟลเดอร์หลักได้รับการปรับปรุงอย่างถูกต้อง

เมื่อทำการทดสอบฉันสังเกตเห็นว่าประสิทธิภาพและการใช้หน่วยความจำสำหรับ ** / * (FDod) นั้นบ้า (มากกว่า 1.4GB สำหรับโฟลเดอร์ 650k เท่านั้น) และอ่านจำนวนมากก่อนที่จะเริ่มสัมผัสโฟลเดอร์ หลังจากแทนที่ด้วย 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

หากคุณไม่ได้ใช้งานสคริปต์ให้แทนที่ "$ @" ด้วยโฟลเดอร์ที่คุณต้องการเรียกใช้


-1

ฉันไม่ชอบความสับสนของคำสั่งเชลล์และทำมันใน python อย่างรวดเร็ว

มันตั้งค่าซ้ำ mtimes ไดเรกทอรีทั้งหมดเป็นไฟล์ที่ไม่รวมใหม่ล่าสุด / dir 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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.