Linuxでファイルを数値ファイル名に一括リネームする方法
Linuxでファイルのセットを数値の順序(1.pdf、2.pdf、3.pdf、...)にリネームしたいですか?これは軽いスクリプトを使って行うことができ、このアーティクルではその方法を正確にお見せします。
数値ファイル名
通常、モバイルフォンや専用のPDFスキャナーなどのハードウェアを使用してPDFファイルをスキャンすると、ファイル名は「2020_11_28_13_43_00.pdf」のようになります。他の多くの半自動システムも、類似の日時に基づいたファイル名を生成します。
場合によっては、ファイルには使用されているアプリケーションの名前や、適用されるDPI(ドット毎インチ)やスキャンされた用紙のサイズなどの他の情報が含まれていることがあります。
異なるソースからPDFファイルを収集する際、ファイル名の規則が大きく異なる場合があるため、数字(または部分的に数字)を用いたファイル名に標準化することが良いかもしれません。
これは他のドメインやファイルセットにも当てはまります。例えば、あなたのレシピや写真コレクション、自動モニタリングシステムによって生成されたデータサンプル、アーカイブ用に準備されたログファイル、データベースエンジニアのためのSQLファイルのセット、そして一般的に異なる命名スキームを持つ異なるソースから収集されたデータなどです。
ファイルを数値ファイル名に一括リネームする
Linuxでは、完全に異なるファイル名の一連のファイルを数値の順番に迅速にリネームするのが簡単です。「簡単」とは、ここでは「実行が容易である」ことを意味します。ファイルを数値に一括でリネームする問題は、自己にコード化するのが複雑です。以下のワンライナースクリプトは、調査、作成、テストに3〜4時間かかりました。試した他の多くのコマンドには、私が避けたかった制限がありました。
保証は一切なく、このコードは「現状のまま」提供されています。実行する前に自分で調査してください。とはいえ、私はさまざまな特殊文字を含むファイルや、50,000以上のファイルに対して成功裏にテストを行い、ファイルが失われることはありませんでした。また、次の名前のファイルも確認しました。
'a'$'n''a.pdf'改行を含む。
if [ ! -r _e -a ! -r _c ]; then echo 'pdf' > _e; echo 1 > _c ;find . -name "*.$(cat _e)" -print0 | xargs -0 -I{} bash -c 'mv -n "{}" $(cat _c).$(cat _e);echo $[ $(cat _c) + 1 ] > _c'; rm -f _e _c; fi
まず、この仕組みを見てから、コマンドを分析しましょう。私たちは、拡張子がすべて同じ.pdfで名前がかなり異なる8つのファイルを持つディレクトリを作成しました。次に、上記のコマンドを実行します:
結果として、8つのファイルは1.pdf、2.pdf、3.pdfなどに名前が変更されましたが、それ以前の名前はかなり異なっていました。
このコマンドは、1.pdfからx.pdfまでの名前のファイルがまだないことを前提としています。もしある場合は、それらのファイルを別のディレクトリに移動し、echo 1をより高い数値に設定して、指定したオフセットで残りのファイルのリネームを開始し、再び2つのディレクトリを統合します。
ファイルを上書きしないように常に注意してください。また、何かを更新する前にクイックバックアップを取ることは常に良いアイデアです。
コマンドを詳しく見てみましょう。xargsに-tオプションを追加することで、裏で何が起こっているのかを見るのに役立ちます:
最初に、コマンドは2つの小さな一時ファイル(名前は_eと_c)を一時ストレージとして使用します。ワンライナーの開始時に、if文を使用して安全チェックを行い、_eと_cの両方のファイルが存在しないことを確認します。その名前のファイルが存在する場合、スクリプトは続行されません。
小さな一時ファイルを使うか変数を使うかというトピックについて言えば、変数を使うのが理想的だったとはいえ(ディスクの入出力がいくらか節約される)、私が直面していた二つの問題がありました。
最初のポイントは、もしオネライナーの最初で変数をEXPORTし、その後で同じ変数を使用する場合、別のスクリプトが同じ変数を使用すると(このスクリプトが同じマシン上で同時に複数回実行されている場合も含めて)、そのスクリプトまたはこのスクリプトが影響を受ける可能性があるということです。そのため、多くのファイルの名前を変更する際には、こうした干渉は避けるのがベストです!
2つ目は、xargsとbash -cの組み合わせが、bash -cコマンドライン内の変数処理に制限があるように見えるということです。オンラインでの広範な調査でも、実用的な解決策が見つかりませんでした。そのため、進行状況を保持する小さなファイル_cを使用することにしました。
_e は私たちが検索して使用する拡張子であり、_c は各リネーム時に自動的に増加するカウンターです。この echo $[ $ (cat _c) + 1 ] > _c コードがそれを処理し、catでファイルを表示し、1を追加し、再書き込みを行います。
このコマンドは、標準の改行終了文字、つまり文字の代わりにヌル終了を使用することで、特殊ファイル名文字を処理する最良の方法を使用します。これは、findの-print0オプションと、xargsの-0オプションによって保証されています。
findコマンドは、_eファイルに指定された拡張子を持つファイルを検索します(これはecho 'pdf' > _eコマンドによって作成されました)。この拡張子は他の任意の拡張子に変更できますが、ドットを前に付けないでください。ドットは後の*.$ (cat _e)-name指定子にすでに含まれています。
ファイルがすべて見つかり、送信されたら、がxargsに送られ、xargsはカウンターファイル(_c)と同じ拡張子ファイル(_e)を使用してファイルの名前を一つずつ変更します。この2つのファイルの内容を取得するために、サブシェル内から実行される単純なcatコマンドが使用されます。
mv コマンドは、既存のファイルを上書きしないために -n オプションを使用します。最後に、2つの一時ファイルを削除してクリーンアップします。
2つの状態ファイルとサブシェルフォークを使用するコストは限られているかもしれませんが、これはスクリプトにいくつかのオーバーヘッドを追加します。特に大量のファイルを扱う場合はそうです。
この同じ問題に対するさまざまな解決策がオンラインにあり、多くの人々が完全に機能する解決策を作ろうとして失敗しました。多くの解決策は、--color=never を指定せずに ls を使用するなど、さまざまなサイドケースを忘れました。これは、ディレクトリリストの色分けが使用される場合に、16進数のコードが解析される原因となる可能性があります。
他のソリューションでも、スペースや改行、''のような特殊文字を正しく処理することができないものがありました。このため、find ... -print0 ... | xargs -0 ...の組み合わせが通常推奨され、理想的です(findとxargsのマニュアルもこの事実を強く示唆しています)。
私の実装が完璧な解決策であるとは考えていませんが、他の多くの解決策に対して重要な進展をもたらすようです。findとで終わる文字列を使用することで、最大のファイル名とパースの互換性を確保し、開始オフセットを指定できるなどのいくつかの他の便利な機能も備えています。また、完全にBashネイティブであります。
楽しんで!


