フォルダのタイムスタンプを最新のファイルに再帰的に変更するには?

フォルダのタイムスタンプを最新のファイルに再帰的に変更するには?

フォルダ内のファイルの最新のタイムスタンプに基づいてフォルダのタイムスタンプを再帰的に変更する方法を知っている人がいるかどうか疑問に思います。

たとえば、

jon@UbuntuPanther:/media/media/MP3s/Foo Fighters/(1997-05-20) 色と形 $ ls -alF
合計 55220
drwxr-xr-x 2 JonJon4096 2010-08-30 12:34 ./
drwxr-xr-x 11 Jon Jon4096 2010-08-30 12:34 ../
-rw-r--r-- 1 jon jon 1694044 2010-04-18 00:51 Spitfire-Doll.mp3
-rw-r--r-- 1 jon jon 3151170 2010-04-18 00:51 スピットファイアほど十分なスペース.mp3
-rw-r--r-- 1 jon jon 5004289 2010-04-18 00:52 Spitfire-Everlong.mp3
-rw-r--r-- 1 jon jon 5803125 2010-04-18 00:51 Spitfire-February Star.mp3
-rw-r--r-- 1 jon jon 4994903 2010-04-18 00:51 フーファイターズ - こんにちは、ジョニーパーク! .mp3
-rw-r--r-- 1 jon jon 4649556 2010-04-18 00:52 スピットファイア - モンキーレンチ.mp3
-rw-r--r-- 1 jon jon 5216923 2010-04-18 00:51 Spitfire-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 Spitfire- New Way Home.mp3
-rw-r--r-- 1 jon jon 2956287 2010-04-18 00:51 Foo Fighters - Goodbye.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 - Follow 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に設定されています。

答え1

現在の時間(または)の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-)" .

ただし、これはファイル名に改行文字がないと仮定します。

答え2

現在のディレクトリとサブディレクトリのすべてのタイムスタンプを更新したい場合現在時刻で:

find . -exec touch {} \;

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

touch -r "$mostrecent" *

したがって、1行は次のようになります。

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

答え4

@Gilles zshコマンドを使用してサブフォルダーで機能するように改善しましたが、** / *(FDod)部分ではzshが非常に非効率的に見えます。

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

引用符を使用すると、スペースとタブを含むディレクトリエントリが正しく機能することがあります。 FDは、odで始まるディレクトリを含む、空でないディレクトリを見つけることを可能にします。深さ優先親フォルダのタイムスタンプが正しく更新されるようにします。

テスト中に** / *(FDod)のパフォーマンスとメモリスペースが狂ったレベル(わずか650,000個のフォルダに対して1.4GB以上)であることがわかり、フォルダをタッチする前に内容全体を読みました。検索/読み取りに置き換えた後、速度が速くなり、メモリを消費せず、ほとんどすぐに起動しました。

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

スクリプトで実行していない場合は、「$@」を実行したいフォルダに置き換えてください。

関連情報