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


16

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

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

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

編集:

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

mv sb_606_HBO_DPM_0089000.dpx sb_606_dpm_0089000.dpx

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

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

4
校閲者へ:これは重複しているとは思わない。シェルのARG_MAX制限と衝突する多数のファイルのために、他の質問に対するCLI回答のほとんどはここでは機能しません。この質問ではコマンドラインソリューションを明示的に要求しているため、他の質問と同様の(おそらく同等の)GUIソリューションも一致しません。
デザート

1
ファイルの名前を変更することについて複数の質問をするのは問題ないので、これはだまされているとは思わない。実際に答えていない一般的なリソースに対して特定の質問を閉じないでください...
Zanna

1
@rich試したコマンドを明示的に編集できる場合、これがだまされていないことは明らかです。(これは、このアプローチを知っていることを示しています。)乾杯。
スパーホーク

2
あなたの質問は特定の質問だからです。心配しないでください。さらに重要なことは、質問が多数の投票された回答を受け取った後、編集すると既存の回答の有効性が低下する可能性があるため、おそらく編集することはお勧めできません。今、私の答えはなぜmv {1..2} {3..4}機能しないのかを説明する必要があると感じていますが、これはまったく異なる問題ARG_MAXです...答えた他の誰もがおそらく同じように感じるでしょう!だから、私の観点から、最後の編集をロールバックし、必要に応じて、mv範囲の変更に関するまったく新しい質問をお願いします
Zanna

1
@Sparhawk OPは、問題の最初のバージョンから、問題はargument list too longエラーであると非常に明確に書いています。さらに明確にする必要はありません。ARG_MAXを処理するための回避策が必要であり、提案された複製の回答はそれをしないため、これは明らかに重複ではありません。
テルドン

回答:


25

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

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

sudo apt install rename

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

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

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


11

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

その他の 資料 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}は、patternから最長のプレフィックス一致を削除し$iます。その最も長いプレフィックスは、すべて、アンダースコア、ゼロまたはそれ以上のゼロとして定義されます。後者は、設定されているオプションに依存*(0)する拡張グロブパターンであると記述されていextglobます。先頭のゼロを削除することは、数値を8 +([0-9])進数ではなく10進数として扱うために重要です。ループ内の引数は別の拡張グロブであり、1つ以上の数字に一致します。数。


ありがとうございました!これは夢のように機能しました:for iの{0089000..0163022}; do mv sb_606_HBO_DPM_ $ i sb_606_dpm_ $ i; 完了-ファイル名拡張子を追加して機能させる必要がありましたが、それは私が望んでいたことであり、構文も理解していました。ありがとう@MvG
リッチ

@rich:お役に立てれば幸いです–あなたと、できれば将来の訪問者も。最も役に立つ答えを受け入れることを忘れないでください。より良いものが出てきたら、いつでもそのチェックマークを変更できます。
MvG

10

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)

7
find . -type f -exec bash -c 'echo $1 ${1/HBO_DPM/dpm}' _ {} \;
./sb_606_HBO_DPM_0089000 ./sb_606_dpm_0089000

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

置換echomvて名前を変更します。


6

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

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

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

python rename.py

6

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

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テストのために。


ザンナの回答に関するコメントを編集しました。ザンナの回答を編集するか、コメントを残してください。
fosslinux

@ubashuは私の答えに対するコメントではありませんでした。-nテストに使用したフラグを参照しており、それを使用することを提案していrename.ulました。
ザンナ

3

誰も私の親友sedをパーティーに招待していないようです:)。次のforループが目標を達成します。

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

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


確かに、この特定のケースにはあまり関連していませんが、ファイル名のいずれかに改行が含まれていると失敗します。ほとんどの(すべて?)他の回答は堅牢であり、任意のファイル名を処理できるか、OPのファイル命名スキームでのみ機能するため、これについて言及します。
テルドン

...改行、スペース、ワイルドカードなど... $iコマンド置換で引用することで回避できるものもありますが、ファイル名の末尾の改行を処理する簡単な方法はありません。
ムール

3

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

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

説明

  • perl -e:で指定されたスクリプトを実行します-e
  • foreach(glob){}{ }グロブの各結果にあるものを実行します。
  • glob("sb_*"):シェルglobに一致する名前を持つ現在のディレクトリ内のすべてのファイルとディレクトリのリストを返しますsb*
  • rename $_, s/_HBO_DPM_/_dpm_/r:perl magic。$_()で繰り返し処理する各要素を保持する特別な変数です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;
}

1

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


ええ、viには見事な検索と置換があります。
ジェイセン

2
あなたの答えを広げて、OPの目標を達成する方法の例を教えていただけますvidirか?
デザート
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.