複数のファイルの名前を親フォルダ名から変更するシェルスクリプト

複数のファイルの名前を親フォルダ名から変更するシェルスクリプト

ファイル構造は次のようになります:

  • 00000010
    • 000000001.ファイル1
    • 000000001.ファイル2
  • 00000020
    • 00000003.ファイル1
    • 00000003.ファイル2
    • 00000003.ファイル3
  • ...

つまり、8 桁の名前を持つフォルダーがあり、その中に 8 桁の数字で始まる名前を持つファイルが 1 つ以上含まれています。しかし、これらのファイル名は、いわば同期されていません。そこで、bash で再帰的に名前を変更してアーカイブ化しようとします。

  • 00000010
    • 000000010.ファイル1
    • 000000010.ファイル2
  • 00000020
    • 00000020.ファイル1
    • 00000020.ファイル2
    • 00000020.ファイル3
  • ...

私のスクリプトは次のようになります:

#! /bin/bash

find * -maxdepth 1 -name "*" -type d | while read -r dir
do
        rename 's/$dir\/[0-9]{8}/$dir/' *
done

しかし、これは機能せず、次のようなエラーが発生します。

グローバル シンボル "$dir" には、(eval 1) の 1 行目に明示的なパッケージ名が必要です。

フォルダ名に応じてファイルの名前を変更するにはどうすればよいでしょうか?

ご協力ありがとうございます!

答え1

別の回答から私が学んだように、私は使用する必要がある

rename "s/$dir\/[0-9]{8}/$dir\/$dir/" $dir/*

万が一、同じ問題を抱えている人がいる場合に備えて...

答え2

パターンに挿入される答えはあまり好きではありません$dir。ディレクトリに、たとえば特殊な正規表現トークンとして解釈される文字が含まれている場合、予期しない結果につながる可能性があります。

ディレクトリをループする必要をなくし、通常の glob を使用するだけで、パターン内でファイルを直接一致させたいと考えています。

rename 's#([^/]+)/[^/]+(\.file[0-9]+)$#$1/$1$2#' base_directory/*/*

ここで、glob はディレクトリ内の個々のファイルに適用されます ( base_directory/*/*.file*、または同様の形式に指定することもできますが、ここでは問題になりません)。

これは、構築を必要としない完全なコマンドであることに注意してくださいfind

  • パターン内でエスケープする必要を回避するために、#「regular」の代わりにセパレーターを使用します。/
  • 私は、「ディレクトリ区切り文字ではない」という (貪欲な) グループをキャプチャし、その後にディレクトリ区切り文字、ファイル名、行末が続きます。これにより、最初のキャプチャ グループが各ファイルの親ディレクトリになります。
  • ファイル名の最初の部分は破棄されますが、序数接尾辞を保持する末尾部分は破棄されます。

ファイルがすべて 8 文字の長さであると想定するのではなく、より一般的なアプローチを使用することを選択しましたが、実際の違いは、構造は必要なく、変数を (おそらく安全でない) 正規表現環境にfind詰め込む必要もないことです。$dir

関連情報