ファイル名の競合なしでファイルの配置で文字列を検索および置換する

ファイル名の競合なしでファイルの配置で文字列を検索および置換する

私は長年にわたって収集されたランダムで無駄なファイル名を持つ何千ものファイルを含むディレクトリツリーを持っています。

私はそれらを整理し、関連性を維持し、特定の単語を削除したいが、重複したファイル名を生成したくないと思います。

例えば

WONDERBROS - PAWG Remy LaCroix Gets BREAKFAST! (pwg11717) - SOMENAME.mp4

次のような名前に変更したいと思います。

WONDERBROS.PAWG.Remy.LaCroix.Gets.BREAKFAST!.(pwg11717).mp4

だからいくつかのポイントがあります。

  • すべてのスペースを次に置き換えます。.
  • SOMENAMEが表示されるたびに削除してください。
  • 名前を変更する前にファイル名がすでに存在することを確認し、数字が追加されたら何も上書きしないように一意のファイル名になるまで続けてください。

シェルスクリプトを通しても可能なようですが、おすすめのツールがあればそれも試してみたいと思います。

似たようなことを試しましたが、最初の行だけが機能しているようです。

# find and replace spaces with .
find /home/matt/rename_test_tmp/ -depth -name "* *" -execdir rename 's/ /./g' "{
# find and replace somename with .
find /home/matt/rename_test_tmp/ -depth -name "somename" -execdir rename 's/ 
# find and replace SOMENAME
find /home/matt/rename_test_tmp/ -depth -name "SOMENAME" -execdir rename 's/ 
# find and replace Somename
find /home/matt/rename_test_tmp/ -depth -name "Somename" -execdir rename 's/ 

私の問題は、私はまだreg exを理解していないということですか?

答え1

これが基本構造です。問題が発生すると、MAXTRYSは名前の変更を停止します。合理的な値を選択してください。

#!/bin/bash
#
# Usage: 
#       numberedMove xy-file.txt TARGETDIR 
#
file="$1"
targetDir="$2"
MAXTRYS=666
#
# @TODO
# add tests for permissions, maybe handle symlinks etc.
#
test -f "$file" || {
    echo No such file "$file" or not an ordinary file
    exit 1;
}

test -d "$targetDir" || {
    echo No such directory "$targetDir"
    exit 2;
}

#
# append NUM+1 to filename, to create unique name
#
numbered () {
  fname="$1"
  num=$2
  if [[ $num -gt $MAXTRYS ]]
  then
    echo " giving up - max trys: $MAXTRYS "
    exit 3
  fi
  # echo "mv $fname → $targetDir/$fname$num"
  test -f "$targetDir/$fname$num" && numbered "$fname" $((num+1)) || mv "$file" "$targetDir/$fname$num"
}

#
# remove all SOMENAME and replace every blank with a dot
#
filtername () {
   fname="$1"
   fname=${fname//SOMENAME/}
   fname=${fname// /.}
   echo "$fname"
}
#
# filter filename, if unique: move, else move with number suffix
#
if [[ -e "$file" ]]
then
    newname=$(filtername "$file")
    if [[ ! -f "$targetDir/$newname" ]]
    then
        # echo "mv $file → $targetDir/$newname"
        mv "$file" "$targetDir/$newname"
    else
        # echo "mv $file → $targetDir/$newname NUMBERED"
        numbered "$newname" 1
    fi
fi

より多くのルールを追加して既存のルールを変更できますfiltername

これが私自身のニーズのためのものであれば、ドットはかなり弱いインジケータ(a.tar.bz2)であるため、スペースを「」。代わりに「-」に変更します。

代わりに、複数の区切り文字を1つに縮小します。

    mv "ab cd - SOMENAME..mp3" → "./B/ab.cd.-...mp3" 
    mv "ab cd - SOMENAME..mp3" → "./B/ab-cd-.mp3" 

ファイル拡張子を保持し、最後の拡張子の前に数字を入れます。

    mv "ab cd- SOMENAME..mp3"  → "./B/ab-cd-0.mp3" 
    mv "ab cd - SOMENAME..mp3" → "./B/ab-cd-1.mp3" 
    mv "ab cd -SOMENAME..mp3"  → "./B/ab-cd-2.mp3" 

多くのプログラムが拡張機能を解釈するためです。

約10個のファイルでのみプログラムをテストしたため使用前にバックアップしてください、操作が成功したことを確認します(合計ファイルサイズとファイル数で可能)。

私のテスト:

for f in a* ; do ./numberedMove.sh "$f" ./B ; done

プログラムをCWDに配置すると、それ自体が移動できることに注意してください。

答え2

Perlの名前変更ユーティリティを使用している場合は、次のことを試してください。

find . -type f -execdir rename -n 's/\s*-\s*/./g; s/\s+/./g; s/somename//ig' {} +

マッチが囲まれて\s*-\s*います-若い- 以上の空白文字(つまり、オプションの空白-を持つ文字) \s+マッチ一つ- またはそれ以上の空白文字。

s/search/replace/名前変更スクリプトに必要なだけコマンドを追加できます。ただし、実行順序に注意を払う必要があります。たとえば、「foo」を「bar」に変更し、「food」を「drink」に変更するには、次のものが必要です。s/food/drink/ 今後 s/foo/bar/後者にfoodなるからだbard

上記のコマンドはすべてのファイル名に適用されます。一部のs/search/replace/コマンドが特定のファイル名に対して機能しない場合、これはエラーではありません。その特定のコマンドは適用されません(ただし、他のコマンドは引き続き適用されます)。それにもかかわらず、特定の名前変更を特定のファイル名にのみ適用するには、述語を使用して複数のfindコマンドを実行する必要があります。-name-iname

複数の単語を同じ代替単語に変更したい場合は、置換を使用することもできます。例えば

s/(somename|someothername|thisname|thatname)//ig

すべて空の文字列に変更します(つまり削除)。修飾子は/i大文字と小文字を区別しません。

-nオプションはrenameテスト実行オプションです。会議名前は変わりましたが、実際には何も名前が変わりません。-n名前変更コマンドが目的の操作を実行し、不要な操作を実行しないことを確認したら、名前変更コマンドからそのコマンドを削除します。名前を変更するときに詳細な出力が必要な場合は、-nを変更してください-v

からman rename

-v-verbose

Verbose:正常に名前が変更されたファイルの名前を印刷します。

-n-nono

ジョブなし:名前を変更するファイル名を印刷しますが、名前を変更しません。


ノート:Perlユーティリティは、新しいファイル名がすでに存在する場合はrenameファイル名を変更しません。競合が発生した場合、ファイル名に数字を追加する機能は組み込まれていませんが、この名前変更の最良の機能の1つは、単純な操作に限定されないことです。たとえば、次のようにs/search/replace/実行できます。どのスクリプトでPerlコードの名前を変更すると、ソースファイル名が変更された名前に変更されます($_明示的な変数名を使用しない場合、s///またはy//暗黙的に同じ演算子が変更されます。ここに新しい説明があります。$_perl$_https://perlmaven.com/the-default-variable-of-perl)。

これは次のことを可能にします(テストされていませんが機能できます)

find . -type f -execdir rename -n '
    s/\s*-\s*/./g; 
    s/\s+/./g;
    s/somename//ig;

    if (-f $_) {
      my $num='001';
      while (-f "$_.$num") {
        $num=sprintf('%03i',++$num);
      };
      $_ = "$_.$num";
    }' {} +

ファイル名がすでに存在する場合は、ファイル名にゼロで埋められた3桁の数字を追加する必要があります(例:from〜001)。 2桁の数字(to)のみが必要な場合は、sprintfからに999変更してください%03i。または、重複ファイルに複数の数字が含まれないようにするには、それをjustに変更してからwhileループ内でnoを使用します。%02i01999my $num=1$num++sprintf()

もう少し作業をすると(ファイル名を「デフォルト名」と「拡張子」部分に分割して)、拡張子の末尾に追加するのではなく、拡張子の前に番号を挿入できます。


renameこのオプションを使用すると、現在使用されているバージョンを確認できます-V。たとえば、私のDebianシステムでは、renameperlの名前変更は次のようになりますが、rename.ulutil-linuxの名前変更は次のようになります。

$ rename -V
/usr/bin/rename using File::Rename version 0.20

$ rename.ul -V
rename.ul from util-linux 2.31.1

答え3

find . -maxdepth 1 -type f > orginal_file

find . -maxdepth 1 -type f -exec sed -r "s/\s+//g"| sed "s/SOMENAME//g" >> /var/tmp/modified file

paste orginal_file /var/tmp/modified file >> combined_orginal_modified_column_wise

for i in `cat /var/tmp/modified file`
do
if [[ -f $i ]]
then
echo "file exsist"
else
awk -v i="$i" '/i/{print "mv" " " $1 " " $2}'   combined_orginal_modified_column_wise
fi
done

for i in `cat /var/tmp/modified file`
do
if [[ -f $i ]]
then
for j in {1..10}
do
elif [[ -f $i$j ]]
then
echo "$i$j exsists"
fi
done
else
awk -v i="$i" -v j="$j" '{print "mv" " " $1 " " ij}'  combined_orginal_modified_column_wise
fi


done

関連情報