フォルダーのタイムスタンプを最新のファイルに再帰的に変更するにはどうすればよいですか?


15

フォルダー内のファイルで見つかった最新のタイムスタンプに基づいてフォルダーのタイムスタンプを再帰的に変更する方法を誰かが知っているのではないかと思っていました。

たとえば、次のとおりです。

jon @ UbuntuPanther:/ media / media / MP3s / Foo Fighters /(1997-05-20)色と形$ ls -alF
合計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-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)The Color and The Shape)のタイムスタンプは2010-04-18 00:52に設定されます。

回答:


20

を使用touch -rして、現在の時間(またはtouch --reference=FILE)の代わりに別のファイルのタイムスタンプを使用できます

2つのソリューションがあります。各ソリューションで、最初のコマンドはディレクトリの変更時刻をその直下の最新ファイルの変更時刻に変更し、2番目のコマンドはディレクトリツリー全体を再帰的に調べます。cd '.../(1997-05-20) The Colour and The Shape'コマンドを実行する前に、ディレクトリ()に移動します。

zshで(Dドットファイルを無視するにはを削除します):

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

Linux(またはより一般的には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-)" .

ただし、これらはファイル名に改行文字がないことを前提としていることに注意してください。


コマンドは機能しますが(Linuxコマンドを使用しました)、再帰的に機能しません。ルートフォルダー(/ media / media / MP3s)でそれを実行しましたが、そこにある他のアーティストのディレクトリとはそれほどうまくいきません。これまでご協力いただきありがとうございます。
MonkeyWrench32

@ 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 \;ます。
ジル「SO-悪であるのをやめる」

完璧!あなたはzshマスターです!:D
MonkeyWrench32

for d in ...以下をどのように適応させることができるのかを使用すると、スペースを含むフォルダでも機能しますか?(それは私のソリューションではまだ不足しています)
-rubo77

@ rubo77あなたが何を言っているのか分かりません。私が投稿したすべてのソリューションは、スペースを含むファイル名で動作します(改行のあるファイル名で失敗するものもあります)。私のソリューションの中にはzshを必要とするものがあることに注意してください。zshでは、変数の置換を二重引用符で囲む必要がありません。
ジル 'SO-悪であるのをやめる'

3

これは「再帰的」ではなく、フォルダー内のすべてのタイムスタンプを変更するだけです。それがあなたの言うことなら、2つのステップがあります。

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 barbar、と同じ修正タイムスタンプを持つように変更されるfooため、フォルダー内のすべてのファイルが、最後に修正されたファイルと同じ修正タイムスタンプを持つように変更されます。

touch -r "$mostrecent" *

したがって、ワンライナーは次のとおりです。

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

lsの出力を解析するのは悪い考えですが、魅力的なケースだと認めています。lsASCII以外の文字を含むファイル名をマングルする場合、依然として危険です。あなたはワンライナー、使用zshのが:-)したい場合
ジル「SO-停止されて悪」

@Gillesそれはそうですが、私はまだそれをする問題に遭遇していません。ファイル名に非ASCII文字が含まれていないためだと思います。しかし、あなたの答えはより良いです
マイケル・ムロゼク

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)のパフォーマンスとメモリフットプリントが非常に悪く(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

シェルコマンドの不明瞭さがあまり気に入らず、すぐに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.