web-dev-qa-db-ja.com

ディレクトリツリー構造を複製し、特定の日付以降に変更された対応するディレクトリにファイルをコピーする

30を超えるサブディレクトリを持つフォルダーがあり、指定した日付(たとえば9月8日など)の後に変更されたファイルのリストを取得し、変更されたものだけを含む同じツリー構造でコピーしたいそのフォルダ内のファイル

私は最後に変更された日付を使用して検索する必要のあるファイルのリストを持っていることから、30 dirを言いましたFindコマンドの出力

a/a.txt
a/b/b.txt
a/www.txt
etc..

たとえば、フォルダ「a」を作成し、その中にa.txtのみを作成したい...他の「a/b」も作成し、その中にb.txtを作成したい...

6
Danny

テキストファイルに目的のファイルがあるとすると、次のようなことができます

while IFS= read -r file; do 
    echo mkdir -p ${file%/*}; 
    cp /source/"$file" /target/${file%/*}/${file##*/}; 
done < files.txt 

リストの各行を読み取り、ディレクトリとファイル名を抽出し、ディレクトリを作成してファイルをコピーします。 sourcetargetを実際に使用している親ディレクトリに変更する必要があります。たとえば、/foo/a/a.txt/bar/a/a.txtにコピーするには、sourcefooに、targetbarに変更します。


allディレクトリをコピーしてから特定のファイルのみをコピーするのか、それともファイルを含むディレクトリだけをコピーするのかは、質問からはわかりません。上記のソリューションでは、必要なディレクトリのみが作成されます。それらすべてを作成したい場合は、

find /source -type d -exec mkdir -p {} /target

これでディレクトリが作成されます。それらができたら、ファイルをコピーするだけです。

while IFS= read -r file; do 
    cp /source/"$file" /target/"$file"
done

更新

この小さなスクリプトは、9月8日以降に変更されたすべてのファイルを移動します。findtouchのGNUバージョンを想定しています。Linuxを使用していると仮定すると、あなたが持っているもの。

#!/usr/bin/env bash    

## Create a file to compare against.
tmp=$(mktemp)
touch -d "September 8" "$tmp"

## Define the source and target parent directories
source=/path/to/source
target=/path/to/target

## move to the source directory
cd "$source"

## Find the files that were modified more recently than $tmp and copy them
find ./ -type f -newer "$tmp" -printf "%h %p\0" | 
    while IFS= read -rd '' path file; do
        mkdir -p "$target"/"$path"
        cp "$file" "$target"/"$path"
    done

厳密に言うと、tmpファイルは必要ありません。ただし、この方法では、同じスクリプトが明日機能します。それ以外の場合、findの-mtimeを使用すると、毎日正しい日付を計算する必要があります。


別のアプローチは、最初にディレクトリを見つけ、ターゲットでそれらを作成し、次にファイルをコピーすることです:

  1. allディレクトリを作成します

    find ./ -type d -exec mkdir -p ../bar/{} \;
    
  2. 関連ファイルを見つけてコピーする

    find ./ -type f -newer "$tmp" -exec cp {} /path/to/target/bar/{} \;
    
  3. 空のディレクトリを削除します

    find ../bar/ -type d -exec rmdir {} \;
    
7
terdon

パックス

Pax は、このタスクに最適なツールです。これはcpiotarのPOSIXに代わるものです(tarとは異なり、アーカイブの作成と抽出だけでなく、パススルーモードも含まれます)。悲しいことに、一部のLinuxディストリビューションではデフォルトのインストールから省略されていますが、これは_apt-get_/yum/emerge /…の呼び出しにすぎません。

Paxには制限があります。コピーするファイルが含まれていない場合でも、最近変更されたディレクトリがコピーされます。空のディレクトリは後で削除できます(保存する宛先に既存の空のディレクトリがない場合)。

_cd /path/to/source
pax -rw -pp -T 201409080000 . /path/to/destination/
find /path/to/destination/ -depth -type d -exec rmdir {} +
_

paxにフィルターがない、類似しているが同一ではないユースケースに適応できる他の方法についても触れます。

Zsh

glob qualifiermを使用して、変更時刻でファイルを一致させます(例:過去10日間に変更されたファイルの場合は_m-10_。代わりに他の単位を使用できます)、および_._通常のファイルと一致します。 履歴修飾子hは、ファイル名のディレクトリ部分を保持します。

_cd /path/to/source
for x in **/*(.m-10); do
  mkdir -p -- $x:h
  cp -p -- $x /path/to/destination/$x
done
_

または、 zmv 関数を使用して、ワイルドカード式で一致したファイルをコピーできます。宛先ディレクトリーを作成する組み込みの方法はないので、それを行う関数を提供します。

_autoload -U zmv
mkdir_cp () {
  mkdir -p -- ${(P)#}:h
  cp -- $@
}
cd /path/to/source
zmv -p mkdir_cp -Q '**/*(.m-10)' '/path/to/destination/$f'
_

POSIX検索

findでは、_-mtime -10_を使用して過去10日間に変更されたファイルを照合するか、_-newer reference_time_を使用して_reference_files_以降に変更されたファイルを照合できます。

_touch -t 201409080000 /tmp/reference_time
cd /path/to/source
find . -type f -newer /tmp/reference_time -exec sh -c '
  mkdir -p /path/to/destination/"${0%/*}"
  cp "$0" "/path/to/destination/$0"
' {} \;
_

これを行うには、findrsyncとともに使用できます。

find ./source/ -newer /tmp/foo -print0 | rsync -av --files-from=- --from0 ./ ./destination/ 

テスト

  1. sourceおよびdestinationという名前の2つのディレクトリを作成しました。
  2. テストのために、次のようなタイムスタンプ付きの一時ファイルを作成しました。

    touch --date "2014-09-08" /tmp/foo
    
  3. ここで、sourceディレクトリ内に、destinationディレクトリにコピーする必要がある一連のサブディレクトリを作成しました(いくつかのサブディレクトリテスト目的で、スペースも含むディレクトリ)。サンプルファイルもいくつか作成しました。 destinationディレクトリは現在空です。

  4. サブディレクトリ内のいずれかのファイルの作成日を変更しました。

    touch -c -t 1110111730 oldfile
    
  5. ここで、指定したfindコマンドを実行します。 findコマンドは、指定した条件に基づいてすべてのファイルを検索し、パイプがrsyncコマンドによって作成されたファイルのリストを取得した後のfindを検索します。

これで、destinationディレクトリ内には、oldfileという名前のファイルが存在しないはずです。

だから、私はdestinationディレクトリの内部を調べて確認します。必要なすべてのサブディレクトリ構造があり、検索条件に一致したすべてのファイルとoldfileという名前のファイルが存在しません。

参照

http://www.commandlinefu.com/commands/view/1481/rsync-find

2
Ramesh

これは、cpioが使用されるように設計された方法とまったく同じです。

find . -whatever -print | cpio -pvmd /path/to/copy/to/.

できました。

1
dgc