如何将文件夹时间戳递归更改为最新文件?


15

我想知道是否有人知道如何基于在该文件夹中找到的文件的最新时间戳来递归更改文件夹的时间戳。

因此,例如:

jon @ UbuntuPanther:/ media / media / MP3s / Foo Fighters /(1997-05-20)颜色和形状$ ls -alF
总计55220
drwxr-xr-x 2乔恩·乔恩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-足够的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-Hey,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

文件夹“(1997-05-20)颜色和形状”的时间戳记将设置为2010-04-18 00:52。

Answers:


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

但是请注意,这些文件假定文件名中没有换行符。


该命令可以工作(我使用Linux的命令),但是它不是递归工作的。我在我的根文件夹(/ media / media / MP3s)中运行了该文件,其余的Artist目录都没有运气。谢谢您到目前为止的帮助。
MonkeyWrench32'9

@ 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 \;
吉尔斯(Gillles)“所以-别再作恶了”

完美!您是zsh的高手!:D
MonkeyWrench32'9

如果您使用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改为具有与相同的修改的时间戳foo,因此这将更改文件夹中的所有文件,使其具有与最近修改的文件相同的修改的时间戳:

touch -r "$mostrecent" *

因此,单线是:

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

解析ls的输出是一个坏主意,尽管我承认这是一个诱人的案例。如果修改ls包含非ASCII字符的文件名仍然存在风险。如果您想要单线,请使用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命令并将其增强以在子文件夹中工作,但是对于** / *(FDod)部分来说,zsh似乎效率极低。

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

引号允许包含空格和制表符的目录条目正常工作。FD使它可以找到非空目录,包括以。开头的目录,od使它以深度优先的方式进行搜索,以便正确更新父文件夹的时间戳。

在测试时,我注意到** / *(FDod)的性能和内存占用非常疯狂(仅650k文件夹就超过1.4GB),并且在开始接触文件夹之前它会读取全部内容。用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

我真的不喜欢shell命令的晦涩之处,因此很快就在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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.