mv を使用して別のディレクトリに移動し、一度に名前を変更する

mv を使用して別のディレクトリに移動し、一度に名前を変更する

100 MB 以上で、過去 1 か月間にアクセスされていないすべてのファイルを知りたいのですが、次のように記述しました。

find / -size +100M -atime +30

そして、これらのファイルを/big-not-usedというフォルダに移動し、名前を次のように変更します。ここfile_nameYYYYMMDDで、file_nameは元のファイル名、YYYYMMDDは今日の日付(年月日)です。たとえば、film.mkv/big-not-used/film.mkv20161031

私の文章は次のようになります:

find / -size +100M -atime +30 -exec mv {} /big-not-used/... \;

しかし、ファイル名に今日の日付を追加する方法がわかりません。次のdate +%Y-%m-%d出力2016-10-31が便利だとわかりました。ここで疑問になるのは、このファイル名を取得する方法です。次のようになります。 https://stackoverflow.com/questions/5456120/how-to-only-get-file-name-with-linux-find

... -exec basename {} \;

多分?:

find / -size +100M -atime +30 -exec mv {} /big-not-used/$(basename {})$(date +%Y-%m-%d) \;

しかし、basename がファイル名ではなくファイルのフルパスで応答するため、エラーが発生します。

${var##/*/}

ファイル名を取得しますが、問題は、basename {}前の式の var に応答するものをどのように挿入するかということです。

多分?

$(${$(basename {})##/*/})

しかし、予期しない '}' の近くに構文エラーがあるようです...

答え1

あなたは次の人と親しくなっていました:

find / -size +100M -atime +30 \
  -exec mv {} /big-not-used/$(basename {})$(date +%Y-%m-%d) \;

しかし、引用符なしでは、シェル$(...)構造の展開が起こる。findコマンドが実行される前につまり、上記のコマンドラインの場合、実際に実行されるのは次のようになります。

find / -size +100M -atime +30 \
  -exec mv {} /big-not-used/{}2016-10-30 \;

の結果は$(basename {})だけなので{}、完全なパス名になります。代わりにこれを試してください:

find / -size +100M -atime +30 \
  -exec sh -c 'mv {} /tmp/big-not-used/$(basename {})$(date +%Y-%m-%d)' \;

mvテストするには、次のように を に置き換えますecho mv

find / -size +100M -atime +30 \
  -exec sh -c 'echo mv {} /tmp/big-not-used/$(basename {})$(date +%Y-%m-%d)' \;

...生成されたコマンドがどのようになるかを確認します。

答え2

私は Lark のソリューションを少し改良して、sh呼び出しを 1 回だけにしました。

find / -size +100M -atime +30 -exec sh -c \
  'for f do mv "$f" /tmp/big-not-used/"$(basename "$f")$(date +%Y-%m-%d)"; done' sh {} +

あるいは、shまったく呼び出しを行わない場合:

while IFS= read -r f; do
  mv "$f" /tmp/big-not-used/"$(basename "$f")$(date +%Y-%m-%d)"
done < <(find / -size +100M -atime +30)

(後者はファイル名に改行が含まれていないことを前提としています。)

デバッグの場合は、(サポートされている場合)-vを追加することをお勧めします。mv

関連情報