
私は大量の画像ファイルを扱っています。その作業の一環として、1000 以上のディレクトリに分散しているすべての画像ファイル タイプを 1 つのディレクトリに移動しました。まったく同じ名前の付いた画像が多数ありましたが、実際には異なる画像でした。そのために、次のワンライナーを使用しました。
find . -type f -exec mv --backup=t '{}' /media/DATA-HDD/AllImages \;
この方法では、同じ名前の画像が上書きされるのではなく、隠しバックアップ ファイルが作成されます。これは非常にうまく機能しましたが、解決しなければならない別の問題があります。
さて、もちろん、次のようなタイルがたくさんあります。
DSC_0616.NEF
DSC_0616.NEF.~1~
DSC_0616.NEF.~2~
私がやりたいのは、コマンド (またはスクリプト) を実行して、ファイル名の末尾にバックアップ番号を追加し、.~[bu#]~ を削除して、隠しファイルではない一意のファイル名にして、これらの隠しファイルの名前を変更することです。つまり、次のようになります。
DSC_0616.NEF
DSC_0616_1.NEF
DSC_0616_2.NEF
私はこれを自分で試すために調査に数時間費やしましたが、このトピックに関する私の知識の範囲内で、そこに到達するのに役立つものは何も見つけることができませんでした。
答え1
すべてが上記のように一貫して命名されていると確信している限り、いくつかの正規表現を使用してシェル スクリプトを通じて作業を完了できます。
#!/bin/bash
# sets the file separator to be only newlines, in case files have spaces in them
IFS=$'\n'
for file in $(find . -type f); do
# parses just the number(s) between two tildes, and only at the end of the file
number=$(echo $file | grep -Eo "~[0-9]+~$" | sed s/'~'/''/g)
# if no match found, assume this is a "base" file that does not need to be renamed
if [ "$number" == "" ]; then
continue
fi
# parses the file name through "NEF", then deletes ".NEF"
filename=$(echo $file | grep -Eio "^.+\.NEF" | sed s/'\.NEF'/''/g )
if [ "$filename" == "" ]; then
continue
fi
mv -v $file $(echo "$filename"_"$number.NEF")
# if anything went wrong, exit immediately
if [ "$?" != "0" ]; then
echo "Unable to move file $file"
exit 1
fi
done
これはディレクトリを下る場合にも機能します。スクリプトを配置し、作業ディレクトリをプロジェクトのディレクトリ ツリーの最上部に置いて実行するだけです。提供したようなサンプル ファイルで実行します。
###@###:~/project$ find . -type f
./DSC_0616.NEF.~8~
./DSC_0616.NEF.~5~
./DSC_0616.NEF.~1~
./DSC_0616.NEF.~7~
./DSC_0616.NEF.~3~
./DSC_0616.NEF.~4~
./DSC_0616.NEF.~9~
./DSC_0616.NEF.~2~
./DSC_0616.NEF.~6~
./lower_dir/DSC_0616.NEF.~8~
./lower_dir/DSC_0616.NEF.~5~
./lower_dir/DSC_0616.NEF.~1~
./lower_dir/DSC_0616.NEF.~7~
./lower_dir/DSC_0616.NEF.~3~
./lower_dir/DSC_0616.NEF.~4~
./lower_dir/DSC_0616.NEF.~9~
./lower_dir/DSC_0616.NEF.~2~
./lower_dir/DSC_0616.NEF.~6~
スクリプトを実行した後:
###@###:~/project$ find . -type f
./DSC_0616_1.NEF
./DSC_0616_3.NEF
./DSC_0616_7.NEF
./DSC_0616_5.NEF
./DSC_0616_2.NEF
./DSC_0616_9.NEF
./DSC_0616_6.NEF
./DSC_0616_8.NEF
./DSC_0616_4.NEF
./lower_dir/DSC_0616_1.NEF
./lower_dir/DSC_0616_3.NEF
./lower_dir/DSC_0616_7.NEF
./lower_dir/DSC_0616_5.NEF
./lower_dir/DSC_0616_2.NEF
./lower_dir/DSC_0616_9.NEF
./lower_dir/DSC_0616_6.NEF
./lower_dir/DSC_0616_8.NEF
./lower_dir/DSC_0616_4.NEF
答え2
コメントで、OP は (.NEF だけでなく) どの拡張子でも機能する解決策を要求していましたが、私も同じ問題を抱えていました。: p
これは、最初の回答よりもやや現代的なバシズムを取り入れたものです。
#!/usr/bin/env bash
# Renames the $1 directory's backup files (produced by `cp` or `mv` with the
# option `--backup=numbered`) such that "foo.png.~17~" becomes "foo_17.png"
function rename_backups()
{
for THING in "${1}"/*
do
if [[ -f "${THING}" &&
"${THING}" =~ ^.+\/+.+\..+~([0-9]+)~$ ]] # Take "foo.png.~17~".
then
# Get the "17".
local BACKUP_NUMBER=${BASH_REMATCH[1]}
# Remove the "~17~", leaving "foo.png".
local SANS_BACKUP_NUMBER="${THING%.*}"
# Get the filename, "foo", and the extension, "png".
local FILENAME="${SANS_BACKUP_NUMBER%.*}"
local EXT="${SANS_BACKUP_NUMBER##*.}"
# Rename to "foo_17.png".
local NEW_NAME="${FILENAME}_${BACKUP_NUMBER}.${EXT}"
while [[ -f "${NEW_NAME}" ]]
do
# If "foo_17.png" already exists for some reason, keep
# increasing the number until we find an unused one.
((++BACKUP_NUMBER))
NEW_NAME="${FILENAME}_${BACKUP_NUMBER}.${EXT}"
done
mv --no-clobber "${THING}" "${NEW_NAME}"
fi
done
}
rename_backups your/backup/directory/here/
以下のバージョンもサポートしています拡張子なしファイル:
#!/usr/bin/env bash
# Renames the $1 directory's backup files (produced by `cp` or `mv` with the
# option `--backup=numbered`) such that:
# - "foo.png.~17~" becomes "foo_17.png"
# - "bar.~17~" becomes "bar_17"
function rename_backups()
{
for THING in "${1}"/*
do
# We'll either have a file like "foo.png.~17~" or "bar.~17~".
if [[ -f "${THING}" && "${THING}" =~ ^.+~([0-9]+)~$ ]]
then
# Get the "17".
local BACKUP_NUMBER=${BASH_REMATCH[1]}
# Remove the "~17~", leaving, e.g., "foo.png".
local SANS_BACKUP_NUMBER="${THING%.*}"
# Get the filename, "foo", and the extension, "png".
local FILENAME="${SANS_BACKUP_NUMBER%.*}"
local EXT="${SANS_BACKUP_NUMBER##*.}"
if [[ "${FILENAME}" == "${SANS_BACKUP_NUMBER}" ]]
then
# This is a "bar.~17~" case, so rename to "bar_17".
local NEW_NAME="${FILENAME}_${BACKUP_NUMBER}"
while [[ -f "${NEW_NAME}" ]]
do
# If "bar_17" already exists for some reason, keep
# increasing the number until we find an unused one.
((++BACKUP_NUMBER))
NEW_NAME="${FILENAME}_${BACKUP_NUMBER}"
done
else
# This is a "foo.png.~17~" case, so rename to "foo_17.png".
local NEW_NAME="${FILENAME}_${BACKUP_NUMBER}.${EXT}"
while [[ -f "${NEW_NAME}" ]]
do
((++BACKUP_NUMBER))
NEW_NAME="${FILENAME}_${BACKUP_NUMBER}.${EXT}"
done
fi
mv --no-clobber "${THING}" "${NEW_NAME}"
fi
done
}
rename_backups your/backup/directory/here/