web-dev-qa-db-ja.com

ファイルの種類と日付に基づいてディレクトリを検索して移動する

200以上のサブディレクトリ「MovieName(year)」を含むディレクトリ「NewMovies」があります。サブディレクトリ「MovieName(year)」には、単一のビデオファイル(avi/mkv)といくつかの関連するjpg/xmlファイルが含まれています。

180日以上経過したビデオファイルを含むすべてのディレクトリを別のディレクトリに移動する必要があります。

例えば:

新しいMovies/Movie A(年)にはmovie.mkv、folder.jpg、movie.xmlが含まれ、すべてのファイルが存在し、そのままの状態で、同じ名前のサブディレクトリに移動したいと思います。

このサイトの他の場所を見た後、私は試しました:

cd "/mnt/user/New Movies/"
find -type f \( -name "*.avi" -or -name ".*mkv" \) -mtime +180 -exec sh -c 'mv "${0%/*}" /mnt/user/Movies' {} \;

このコマンドは、最初のサブディレクトリとすべてのファイルを新しいホームに正常に移動しますが、これ以降のすべての操作でエラーが返されます。

find: './Movie B (year)': No such file or directory
find: './Movie C (year)': No such file or directory

移動予定かどうかに関係なく、「新しい映画」の下に含まれるすべてのディレクトリを介して以下同様に続きます。

2
Justin

findによって現在検査されているディレクトリを_-exec mv_しないでください。そうすると、findが混乱するようです。

回避策:最初にディレクトリを見つけてから移動します。

_cd "/mnt/user/New Movies/"
find -type f \( -name "*.avi" -or -name ".*mkv" \) -mtime +180 \
  -printf "%h\0" | xargs -0 mv -t /mnt/user/Movies
_

説明:

  • _-printf_は、フォーマット文字列に従って一致を出力します。
  • _%h_は、一致のパス部分を出力します。これは、コマンドの_"${0%/*}"_に対応します。
  • _\0_は、ヌル文字を使用して項目を区切ります。これは、ファイル名に改行が含まれている場合の予防策です。
  • xargsはパイプから入力を収集し、入力を追加して引数を実行します。
  • _-0_は、入力が改行で区切られるのではなくnullで区切られることを期待するようにxargsに指示します。
  • _mv -t <target>_を使用すると、すべてのソース引数を最後に追加してmvを呼び出すことができます。

これはまだ絶対に安全ではないことに注意してください。パイプバッファと組み合わせた一部の異常なスケジューラのタイミングにより、mvがディレクトリから移動する前にfindが実行される可能性があります。それさえ防ぐためにあなたはこのようにそれをすることができます:

_cd "/mnt/user/New Movies/"
find -type f \( -name "*.avi" -or -name ".*mkv" \) -mtime +180 \
  -printf "%h\0" > dirstomove
xargs -0 mv -t /mnt/user/Movies < dirstomove
_

背景説明:

あなたのfindで何が起こるかは次のとおりだと思います。

  1. findはディレクトリ_/mnt/user/New Movies/_をトラバースします。そこにいる間、キャッシュ内の利用可能なディレクトリに注意します。
  2. findは、システムコールchdir(subdirname)を使用してサブディレクトリの1つに移動します。
  3. 内部findは、フィルターを通過するムービーファイルを検索します。
  4. findは、指定されたパラメーターを使用してmvを実行します。
  5. mvはディレクトリを_/mnt/user/Movies_に移動します。
  6. findは、システムコールchdir(..)を使用して親ディレクトリに戻ります。これは、_/mnt/user/Movies_ではなく_/mnt/user/New Movies/_を指すようになりました。
  7. findは、前にメモしたディレクトリが見つからず、多くのエラーをスローするため、混乱しています。

この仮定は、この質問への回答に基づいています: find -exec mvは最初のexecの後に停止します 。その場合、なぜfindが機能しなくなり、エラーが発生するのかわかりません。 findの異なるバージョンが説明かもしれません。

0
lesmana

[〜#〜] ifs [〜#〜]環境変数をIFS=$(echo -en "\n\b");に設定すると、シェルはスペースではなく改行に基づいてアイテムを区切ります。

さらに、この-exec sh -c 'mv "${0%/*}" /mnt/user/Movies' {} \;は非常に奇妙です。私が間違っていない場合は、-exec mv {} /mnt/user/Movies \;に単純化してください

0
justbrowsing