他のサブフォルダのファイル名を変更する

他のサブフォルダのファイル名を変更する

別のフォルダにある複数のファイルの名前を変更したいと思います。具体的には、ファイル名の中間にゼロを追加して、すべてのファイル名が3桁の数字を持つように(したがって論理的な順序で表示されるように)したいと思います。

より具体的には、各フォルダには400を超える.niiファイルを含む130を超えるフォルダがあります。各 .nii ファイルには次のパターンがあります。

swu_run1_P_139_Vol_1.nii

  • P_###の範囲はP76~P277(参加者番号)です。
  • Vol_###の範囲は1~405(ボリューム番号)

ボリュームの範囲は 1 から 405 であるため、これはすべてのリストが 1-405 ではなく 100 で始まることを意味します。たとえば、100 - 101 - 102 [..] - 109 - で始まります。10- 110〜111など)。この問題を解決する1つの方法は、ファイル名に0を追加し、すべてを3桁の数字にすることです。たとえば、次のようになります。

swu_run1_P_277_Vol_1.nii -> swu_run1_P_277_Vol_001.nii
swu_run1_P_277_Vol_2.nii -> swu_run1_P_277_Vol_002.nii
swu_run1_P_277_Vol_10.nii -> swu_run1_P_277_Vol_010.nii
swu_run1_P_277_Vol_120.nii -> swu_run1_P_277_Vol_120.nii

私はUnix / Linuxシステムの経験がほとんどありませんが、前のスレッドを使用して次のコードを思いつきました。 2つの部分で構成されています。

1. ファイル名の途中にゼロを追加して、複数のファイル名を変更します。

rename Vol_ Vol_0 *Vol_[0-9].nii

サブフォルダから実行すると、次のエラーメッセージが表示されます。

Error: rename: swu_run1_P_275_Vol_1.nii: rename to swu_run1_P_275_Vol_01.nii failed: No such file or directory

奇妙なことに、Vol_1-9には0が追加されます。ただし、すでに2桁または3桁の数字を持つ数字には0を追加しません。

swu_run1_P_277_Vol_1.txt -> swu_run1_P_277_Vol_01.nii
swu_run1_P_277_Vol_10.txt -> swu_run1_P_277_Vol_10.nii
swu_run1_P_277_Vol_100.txt -> swu_run1_P_277_Vol_100.nii

式に奇妙なループがあるようです(新しいVol_01を変更しようとするとエラーメッセージが表示されます)。 2桁/3桁の数字にゼロを追加しないのはなぜですか?

2..nii関連サブフォルダー内のすべてのファイルを検索し、バッチの名前変更を実行します。

find . -iname "*.nii" -execdir rename Vol_ Vol_0 *Vol_[0-9].nii '{}' \;

このコードの私の理解は次のとおりです。

  • find . -iname "*.nii"現在のフォルダとサブフォルダ内のすべての.niiファイルを検索する

  • -execdir現在のフォルダとサブフォルダに次の式を適用するように指示します。つまり、ゼロを追加します。

  • rename Vol_ Vol_0 *Vol_[0-9].nii0追加(次の形式を使用)テキストから 文字通り ファイル一覧)

  • '{}'ファイルのパス名があります

  • \;-execdir式を終了できますか?

より多くのフォルダでコードを実行しようとすると、次のエラーメッセージが表示されます。

Error: rename: *Vol_[0-9].nii: rename to *Vol_0[0-9].nii failed: No such file or directory

-execdirがサブフォルダで実行されていないため、エラーメッセージが表示されるようですが、この問題を解決する方法がわかりません。

シェルを実行するために手動で各サブフォルダに移動したくありません。このコードを改善して機能させる方法に関する提案はありますか? 「該当するファイルやディレクトリはありません。」エラーメッセージが表示されるのはなぜですか?

答え1

swu_run1_P_277_Vol_1.nii変数に名前がある場合はnameそう${name##*_}です1.nii(最も長いプレフィックス文字列の一致が*_削除されます)。

インポートして削除したら、.nii3文字の幅でゼロパディングしたい数字を取得します。

name=swu_run1_P_277_Vol_1.nii

number=${name##*_}
number=${number%.nii}

bashシェルで数字をゼロパッドする最も簡単な方法は次のとおりですprintf

printf '%.3d' "$number"    # would print 001 (with no newline)

同時に新しい名前を設定できます。

printf '%s_%.3d.nii' "${name%_*.nii}" "$number"

このprintfコマンドは、swu_run1_P_277_Vol_001.nii元の名前から一致するサフィックス文字列を削除し、ゼロで埋められた数字を追​​加してから、サフィックス文字列を追加して印刷します。_*.nii_.nii

最も重要なのは、結果の文字列を印刷できることです。まっすぐ新しい変数としてprintf -v newname ...

1つの名前で一緒に使用してください。

name=swu_run1_P_277_Vol_1.nii

number=${name##*_}
number=${number%.nii}

printf -v newname '%s_%.3d.nii' "${name%_*.nii}" "$number"

まあ、それはただの質問ですmv "$name" "$newname"

いいですね。すべての関連ファイルに対してこれをどのように実行しますか?

すべての関連ファイルがワイルドカードパターンと一致すると仮定する*Vol_*.niifind

find . -type f -name '*Vol_*.nii' -exec bash -c '
    for pathname do
        dirpath=${pathname%/*}  # or: dirpath=$(dirname "$pathname")
        name=${pathname##*/}    # or: name=$(basename "$pathname")

        number=${name##*_}
        number=${number%.nii}

        printf -v newname "%s_%.3d.nii" "${name%_*.nii}" "$number"

        printf "Would rename %s --> %s\n" "$pathname" "$dirpath/$newname"
        # mv "$pathname" "$dirpath/$newname"
    done' bash {} +

bash -cここのインラインスクリプトは、(通常のファイルです)および(特定の名前を持つ)条件を満たすパスfind名を使用して一括して呼び出されます。スクリプトはこれらのパス名を繰り返してファイル名を抽出し、ディレクトリパス名を 。-type f-namenamedirpath

次に、以前に行ったのと同じ操作を実行して、に保存されている新しい名前を取得し、ファイルのnewname名前を変更します。

mvまあ、私は安全のために実際のコマンドをコメントアウトしました。出力が正しいことを確認するには、まず一度実行する必要があります。 GNUツールを使用している場合、mv -b名前の競合がある場合はそれを使用してファイルをバックアップすることもできます。


ちなみに、シェルzshではワイルドカードパターン

./**/*Vol_*.nii(n)

これはすべての名前に展開されます。番号順に(そしてintサブディレクトリに再帰的に移動します):

$ print -rC1 ./**/*Vol_*.nii(n)
./swu_run1_P_277_Vol_1.nii
./swu_run1_P_277_Vol_2.nii
./swu_run1_P_277_Vol_10.nii
./swu_run1_P_277_Vol_120.nii

関連情報