macOSでfindとmvを使用してディレクトリの名前を変更する

macOSでfindとmvを使用してディレクトリの名前を変更する

ディレクトリとファイルの名前を変更するコマンドで問題が発生しています。

  • オペレーティングシステム:MACOS 11.4
  • 目的:スペースをアンダースコアに変更するディレクトリとファイルの名前を変更する_
  • 試してみるコマンド:
    find . -maxdepth 1 -iname "* *" -exec sh -c 'fichier="{}"; mv -- $fichier ${fichier// /_}' \;
    

find私は一度に1レベルの深さのディレクトリツリーをナビゲートできるようにしたいので、これを使います。

このコマンドの結果は次のとおりです。

usage: mv [-f | -i | -n] [-v] source target
       mv [-f | -i | -n] [-v] source ... directory

だからmv私はechoコマンドをチェックするために使用しません

find . -maxdepth 1 -iname "* *" -exec sh -c 'fichier="{}"; echo $fichier ${fichier// /_}' \;

これは期待通りに動作するようです。

./Job offers etc ./Job_offers_etc
./School results ./School_results
./Famille et Souvenirs ./Famille_et_Souvenirs
./KID education ./KID_education
./Template Open Office-MS Office ./Template_Open_Office-MS_Office
./Mode Emplois ./Mode_Emplois
./cartres de voeux ./cartres_de_voeux

私がそれを使用したときに何が間違っていましたかmv

答え1

現在経験している状況は、これが推奨される理由の1つです。(ほぼ)常にシェル変数を引用します。

あなたの場合、シェル変数にfichierスペースを含むファイル名を指定したので、変数を「現状のまま」使用すると、シェルはトークン化を実行します。つまり、引数であるディレクトリは次のようになります$fichier。 3つのファイルを宛先ディレクトリに移動します(1)Job offers etcmvJoboffersetcJob_offers_etc

この問題を回避するには、に示すように変数参照の周りに二重引用符を入れます"$fichier"


(1)これは実際に危険です。ターゲットディレクトリが存在しない場合、このコマンドは3つのファイル名を同じ名前に変更して、最初の2つのファイルを3番目のファイルで上書きできます。

答え2

Perlの名前変更ユーティリティがある場合ファイル::名前の変更、既にインストールされているので簡単です。まだしていない場合は、しなければならないインストールしてください。難しいバッチの名前変更操作は非常に簡単になります。

お持ちの場合自分で作ったインストールされている場合は、次のコマンドを使用してインストールできますbrew install rename(参照:抽出時に名前を変更する)それ以外の場合はインストールできますcpan。同様に、MacにHomebrewがインストールされていない場合しなければならない、何千ものパッケージへのアクセスを提供します。

その後、現在のディレクトリのすべてのファイル名+ディレクトリ名のスペースを下線で置き換えることができます。

rename -n 's/ /_/g' *

この-nオプションを使用すると、テストで実行でき、実際にはファイル名を変更せずに名前を変更した内容のみを表示します。必要に応じて動作することを確認したら、オプションを削除するか、詳細な出力に-n置き換えてください。-v

Perl renameは、名前変更スクリプトが実際にファイル名を変更した場合にのみファイル名を変更しようとし、上記のスクリプトはスペースなしでファイル名を変更しないため、スペースを含まないファイルを除外する必要はほとんどまたはまったくありません。

また、強制的に実行しない限り、既存のファイル名にファイル名を変更することを拒否します-f

必要に応じて find で使用でき、NUL で区切られた入力を理解します (したがって、改行を含むthoseファイル名も含めてすべてのファイル名を処理できます)。例えば

find . -maxdepth 1 -iname "* *" -print0 | rename -0 -n 's/ /_/g'

答え3

findとの組み合わせsh -cと変数参照の必要性のため、ループを使用する方が簡単ですfor

for file in *\ *
do
  newfile=$(echo "$file" | tr ' ' _)
  mv -i "$file" "$newfile"
done

関連情報