web-dev-qa-db-ja.com

多数の画像ファイルの名前をbashで変更する

私は約名前を変更する必要があります。 70,000ファイル。例:sb_606_HBO_DPM_0089000からsb_606_dpm_0089000など。

番号の範囲は0089000から0163022までです。変更する必要があるのは、名前の最初の部分だけです。すべてのファイルは単一のディレクトリにあり、順番に番号が付けられます(イメージシーケンス)。番号は変更しないでください。

これをbashで試すと、「引数リストが長すぎる」とグリズリングします。

編集:

私は最初に単一のファイルの名前をmvで変更しようとしました:

mv sb_606_HBO_DPM_0089000.dpx sb_606_dpm_0089000.dpx

次に、範囲の名前を変更しようとしました(先週、ここで大量のファイルを移動する方法を学びましたので、ファイルの名前を変更するために同じ構文が機能すると考えました...)。 I 思考私は次の(またはそれに似た)を試しました:

mv sb_606_HBO_DPM_0{089000..163023}.dpx sb_606_dpm_0{089000..163023}.dpx
16
rich

1つの方法は、find-execとともに使用し、+オプションを使用することです。これは引数リストを作成しますが、リストを必要な数の呼び出しに分割して、最大引数リストを超えずにすべてのファイルを操作します。すべての引数が同じように扱われる場合に適しています。これはrenameの場合ですが、mvの場合ではありません。

Perl renameのインストールが必要になる場合があります。

Sudo apt install rename

次に、たとえば、次を使用できます。

find . -maxdepth 1 -exec rename -n 's/_HBO_DPM_/_dpm_/' {} +

実際にファイルの名前を変更するには、テスト後に-nを削除します。

25
Zanna

3つの代替案を提案します。それぞれは単純な単一行コマンドですが、主に処理するファイルが同じディレクトリ内の他のファイルと混在している場合に備えて、より複雑な場合のバリアントを提供します。

mmv

同じ名前のパッケージ から mmvコマンド を使用します。

mmv '*HBO_DPM*' '#1dpm#2'

引数は文字列として渡されるため、シェルではグロブ展開が行われないことに注意してください。このコマンドは正確に2つの引数を受け取り、対応するファイルを内部的に検索します。ファイル数に厳しい制限はありません。また、上記のコマンドは、最初のグロブに一致するすべてのファイルの名前が変更されることを前提としていることに注意してください。もちろん、もっと具体的にすることは自由です:

mmv 'sb_606_HBO_DPM_*' 'sb_606_dpm_#1'

同じディレクトリに要求された番号範囲外のファイルがある場合、この回答でさらに下に指定された番号のループを使用する方がよい場合があります。ただし、適切なパターンでmmv呼び出しのシーケンスを使用することもできます。

mmv 'sb_606_HBO_DPM_0089*'       'sb_606_dpm_0089#1'    # 0089000-0089999
mmv 'sb_606_HBO_DPM_009*'        'sb_606_dpm_009#1'     # 0090000-0099999
mmv 'sb_606_HBO_DPM_01[0-5]*'    'sb_606_dpm_01#1#2'    # 0100000-0159999
mmv 'sb_606_HBO_DPM_016[0-2]*'   'sb_606_dpm_016#1#2'   # 0160000-0162999
mmv 'sb_606_HBO_DPM_01630[01]?'  'sb_606_dpm_01630#1#2' # 0163000-0163019
mmv 'sb_606_HBO_DPM_016302[0-2]' 'sb_606_dpm_016302#1'  # 0163020-0163022

数字をループする

何もインストールしないようにする場合、またはこの範囲外の一致を避けるために番号範囲で選択する必要があり、74,023個のコマンド呼び出しを待機する準備ができている場合は、単純なbashループを使用できます。

for i in {0089000..0163022}; do mv sb_606_HBO_DPM_$i sb_606_dpm_$i; done

シーケンスにギャップがないため、これはここで特にうまく機能します。それ以外の場合は、ソースファイルが実際に存在するかどうかを確認することをお勧めします。

for i in {0089000..0163022}; do
  test -e sb_606_HBO_DPM_$i && mv sb_606_HBO_DPM_$i sb_606_dpm_$i
done

for ((i=89000; i<=163022; ++i))とは対照的に、数年前に一部のBashがリリースされて以来、ブレース展開は先行ゼロを処理することに注意してください。実際に私が要求した変更であるため、使用例が表示されてうれしいです。

さらに読む:ブレース展開 Bash情報ページ、特に{x..y[..incr]}に関する部分。

ファイルのループ

別のオプションは、問題の整数範囲を単にループするのではなく、適切なグロブをループすることです。このようなもの:

for i in *HBO_DPM*; do mv "$i" "${i/HBO_DPM/dpm}"; done

繰り返しますが、これはファイルごとにmv呼び出しです。繰り返しますが、ループは要素の長いリストに対して行われますが、リスト全体がサブプロセスへの引数として渡されるのではなく、bashによって内部的に処理されるため、制限は問題を引き起こしません。

さらに読む:Shell Parameter Expansion Bash情報ページで、特に${parameter/pattern/string}を文書化。

番号範囲を指定したものに制限する場合は、そのためのチェックを追加できます。

for i in sb_606_HBO_DPM_+([0-9]); do
  if [[ "${i##*_*(0)}" -ge 89000 ]] && [[ "${i##*_*(0)}" -le 163022 ]]; then
    mv "$i" "${i/HBO_DPM/dpm}"
  fi
done

ここで${i##pattern}は、$iからpatternに一致する最長のプレフィックスを削除します。その最も長いプレフィックスは、すべて、アンダースコア、ゼロまたはそれ以上のゼロとして定義されます。後者は、拡張された glob pattern である*(0)として記述されます。これは、設定されている extglob option に依存します。先頭のゼロを削除することは、数値を基数8ではなく基数10として扱うために重要です。ループ引数の+([0-9])は、同じ開始文字であるが数字で終わらない.

11
MvG

ARG_MAXの制限を回避する1つの方法は、bashシェルの組み込みprintfを使用することです。

printf '%s\0' sb_* | xargs -0 rename -n 's/HBO_DPM/dpm/'

例.

rename -n 's/HBO_DPM/dpm/' sb_*
bash: /usr/bin/rename: Argument list too long

しかし

printf '%s\0' sb_* | xargs -0 rename -n 's/HBO_DPM/dpm/'
rename(sb_606_HBO_DPM_0089000, sb_606_dpm_0089000)
.
.
.
rename(sb_606_HBO_DPM_0163022, sb_606_dpm_0163022)
10
steeldriver
find . -type f -exec bash -c 'echo $1 ${1/HBO_DPM/dpm}' _ {} \;
./sb_606_HBO_DPM_0089000 ./sb_606_dpm_0089000

find現在のディレクトリ.すべてのファイル-type fに対して、$1HBO_DPMdmpに置き換えて、見つかったファイルの名前を変更します 1つずつ-exec ... \;

名前変更を実行するには、echomvに置き換えます。

7
αғsнιη

あなたはそれをファイルごとに行うことができます(時間がかかる場合があります)

Sudo apt install util-linux  # if you don't have it already
for i in *; do rename.ul HBO_DPM dpm "$i"; done

他の回答で使用されるPerl renameと同様に、rename.ulにはテスト用の-nまたは--no-actオプションもあります。

6
muclux

次のような小さなpythonスクリプトを作成できます。

import os
for file in os.listdir("."):
    os.rename(file, file.replace("HBO_DPM", "dpm"))

これをテキストファイルとしてrename.pyとしてファイルが保存されているフォルダーに保存し、そのフォルダーのターミナルを使用して移動します。

python rename.py
6
Stone Skull

オプションを提供しているので、ここにPerlのアプローチがあります。 cdをターゲットディレクトリに移動して実行します。

Perl -e 'foreach(glob("sb_*")){rename $_, s/_HBO_DPM_/_dpm_/r}'

説明

  • Perl -e-eで指定されたスクリプトを実行します。
  • foreach(glob){}:グロブの各結果に対して{ }にあるものを実行します。
  • glob("sb_*"):現在のディレクトリ内で、Shell glob sb*と一致する名前を持つすべてのファイルとディレクトリのリストを返します。
  • rename $_, s/_HBO_DPM_/_dpm_/r:Perlマジック。 $_は、繰り返し処理する各要素(foreach内)を保持する特別な変数です。したがって、ここでは、見つかった各ファイルになります。 s/_HBO_DPM_/_dpm_/は、最初に出現する_HBO_DPM__dpm_に置き換えます。デフォルトでは$_で実行されるため、各ファイル名で実行されます。 /rは、「この置換をターゲット文字列(ファイル名)のコピーに適用し、変更された文字列を返すことを意味します。renameは、期待どおりの動作をします。 $__HBO_DPM_に置き換えて、現在のファイル名(_dpm_)の名前を変更します。

拡張された(そしてより読みやすいスクリプト)と同じことを書くことができます:

#! /usr/bin/env Perl
use strict;
use warnings;

foreach my $fileName (glob("sb_*")){
  ## Copy the name to a new variable
  my $newName = $fileName;
  ## change the copy. $newName is now the changed version
  $newName =~ s/_HBO_DPM_/_dpm_/;
  ## rename
  rename $fileName, $newName;
}
3
terdon

私の親友sedをパーティーに招待した人は誰もいません。次のforループが目標を達成します。

for i in sb_606_HBO_DPM*; do
  mv "$i" "$(echo $i | sed 's/HBO_DPM/dpm/')";
done

このようなジョブには多くのツールがありますが、最も理解しやすいツールを選択してください。これはシンプルで、この目的や他の目的に合わせて簡単に変更できます...

3
andrew.46

想定している名前の変更の種類によっては、複数行の編集で vidir を使用しても十分な場合があります。
特定のケースでは、テキストエディターですべての行を選択し、いくつかのキーストロークでファイル名の_ "HBO"部分を削除できます。

1
kraymer