web-dev-qa-db-ja.com

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

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

だから例えば:

 jon @ UbuntuPanther:/ media/media/MP3s/Foo Fighters /(1997-05-20)色と形$ 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ジョンジョン1694044 2010-04-18 00:51 Foo Fighters-Doll.mp3 
-rw-r--r-- 1ジョンジョン3151170 2010-04-18 00:51 Fooファイターズ-十分なスペース.mp3 
-rw-r--r-- 1ジョンジョン5004289 2010-04-18 00:52フーファイターズ-Everlong.mp3 
-rw-r--r -1ジョンジョン5803125 2010-04-18 00:51フーファイターズ-2月のスター.mp3 
-rw-r--r-- 1ジョンジョン4994903 2010-04-18 00:51フーファイターズ-ねえ、ジョニーパーク!.mp3 
-rw-r--r-- 1 jon jon 4649556 2010-04-18 00:52 Foo Fighters-Monkey Wrench.mp3 
-rw-r- -r-- 1ジョンジョン5216923 2010-04-18 00:51 Foo Fighters-My Hero.mp3 
-rw-r--r-- 1ジョンジョン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-Walk 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に設定されます。

16
MonkeyWrench32

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

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

ただ使う

find . -exec touch {} \;
3
Daz

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

stat -c '%Y' filenamefilenameのタイムスタンプを出力し、stat -c '%Y %n' *は、フォルダー内のすべてのファイルのタイムスタンプとファイル名を出力するため、現在のフォルダー内で最後に変更されたファイルのファイル名を検索します。

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

考え直してみると、フォルダ内で最高のタイムスタンプを取得するためのwayより簡単な方法があります。

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

次に、フォルダー内のすべてのファイルを、そのファイルと同じタイムスタンプを持つように変更します。 touch -r foo barbarfooと同じ変更されたタイムスタンプを持つように変更します。これにより、フォルダー内のすべてのファイルが最後に変更されたファイルと同じ変更されたタイムスタンプを持つように変更されます。

touch -r "$mostrecent" *

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

touch -r "`ls -t | head -n1`" *
3
Michael Mrozek

私はこの仕事をまとめました:

これは、/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
2
rubo77

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

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

引用符を使用すると、スペースとタブを含むディレクトリエントリが正しく機能します。 FDは、。で始まるものを含む空でないディレクトリを見つけさせます。odはdepth-firstの方法で検索するため、親フォルダのタイムスタンプが適切に更新されます。

テストしたところ、**/*(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

スクリプトで実行していない場合は、「$ @」を実行元のフォルダーに置き換えます。

0
Aaron Queenan

このスクリプトを使用して、フォルダーのタイムスタンプを最新のコンテンツに再帰的に設定します。 (これは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
mivk