30を超えるサブディレクトリを持つフォルダーがあり、指定した日付(たとえば9月8日など)の後に変更されたファイルのリストを取得し、変更されたものだけを含む同じツリー構造でコピーしたいそのフォルダ内のファイル
私は最後に変更された日付を使用して検索する必要のあるファイルのリストを持っていることから、30 dirを言いましたFindコマンドの出力
a/a.txt
a/b/b.txt
a/www.txt
etc..
たとえば、フォルダ「a」を作成し、その中にa.txtのみを作成したい...他の「a/b」も作成し、その中にb.txtを作成したい...
テキストファイルに目的のファイルがあるとすると、次のようなことができます
while IFS= read -r file; do
echo mkdir -p ${file%/*};
cp /source/"$file" /target/${file%/*}/${file##*/};
done < files.txt
リストの各行を読み取り、ディレクトリとファイル名を抽出し、ディレクトリを作成してファイルをコピーします。 source
とtarget
を実際に使用している親ディレクトリに変更する必要があります。たとえば、/foo/a/a.txt
を/bar/a/a.txt
にコピーするには、source
をfoo
に、target
をbar
に変更します。
allディレクトリをコピーしてから特定のファイルのみをコピーするのか、それともファイルを含むディレクトリだけをコピーするのかは、質問からはわかりません。上記のソリューションでは、必要なディレクトリのみが作成されます。それらすべてを作成したい場合は、
find /source -type d -exec mkdir -p {} /target
これでディレクトリが作成されます。それらができたら、ファイルをコピーするだけです。
while IFS= read -r file; do
cp /source/"$file" /target/"$file"
done
この小さなスクリプトは、9月8日以降に変更されたすべてのファイルを移動します。find
とtouch
の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
を使用すると、毎日正しい日付を計算する必要があります。
別のアプローチは、最初にディレクトリを見つけ、ターゲットでそれらを作成し、次にファイルをコピーすることです:
allディレクトリを作成します
find ./ -type d -exec mkdir -p ../bar/{} \;
関連ファイルを見つけてコピーする
find ./ -type f -newer "$tmp" -exec cp {} /path/to/target/bar/{} \;
空のディレクトリを削除します
find ../bar/ -type d -exec rmdir {} \;
Pax は、このタスクに最適なツールです。これはcpio
とtar
の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
にフィルターがない、類似しているが同一ではないユースケースに適応できる他の方法についても触れます。
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'
_
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"
' {} \;
_
これを行うには、find
をrsync
とともに使用できます。
find ./source/ -newer /tmp/foo -print0 | rsync -av --files-from=- --from0 ./ ./destination/
テスト
テストのために、次のようなタイムスタンプ付きの一時ファイルを作成しました。
touch --date "2014-09-08" /tmp/foo
ここで、sourceディレクトリ内に、destinationディレクトリにコピーする必要がある一連のサブディレクトリを作成しました(いくつかのサブディレクトリテスト目的で、スペースも含むディレクトリ)。サンプルファイルもいくつか作成しました。 destinationディレクトリは現在空です。
サブディレクトリ内のいずれかのファイルの作成日を変更しました。
touch -c -t 1110111730 oldfile
ここで、指定したfind
コマンドを実行します。 find
コマンドは、指定した条件に基づいてすべてのファイルを検索し、パイプがrsync
コマンドによって作成されたファイルのリストを取得した後のfind
を検索します。
これで、destinationディレクトリ内には、oldfile
という名前のファイルが存在しないはずです。
だから、私はdestination
ディレクトリの内部を調べて確認します。必要なすべてのサブディレクトリ構造があり、検索条件に一致したすべてのファイルとoldfile
という名前のファイルが存在しません。
参照
これは、cpio
が使用されるように設計された方法とまったく同じです。
find . -whatever -print | cpio -pvmd /path/to/copy/to/.
できました。