it-swarm-ja.com

すべてのファイル名で空白をアンダースコアに置き換える方法は?

以下のスクリプトは、特定のフォルダにあるすべてのファイル名に「空白」ではなく「アンダースコア」を配置します。フォルダだけでなく、すべてのサブフォルダとそれに含まれるファイルの名前に「空白」ではなく「アンダースコア」を配置するシェルスクリプトを作成するのに問題があります。

誰かがこれを行う方法について何かヒントがありますか?

これが私のコードです:

#!/bin/bash
ls | while read -r FILE; do
  mv -v "$FILE" `echo $FILE | tr ' ' '_'`
done
2
Rafael

代わりに rename utility を使用してください。

rename "s/ /_/g" *

多くの便利な組み込みを備えたPerlベースのファイル名前変更スクリプト。


再帰的な名前変更については、次を試してください。

rename "s/ /_/g" **/*.*

ここで、**Bashグロブオプションshopt -s globstarで有効化)です。

または、findを使用します。

find . -type f -execdir rename "s/ /_/g" {} ';'
3
kenorb

検索を使用して、dirとsubdirを検索します。

_while IFS='' read -r -d '' fname ; do
   nname="${fname##*/}"
   mv -v -n "${fname}"  "${fname%/*}/${nname//[[:space:]]/_}"
done < <(find "$(pwd)"  -name "* *" -type f  -print0)
_

find "$(pwd)" -type f -print0-現在のディレクトリとサブディレクトリで見つかったすべてのファイルパスを出力します。

プロセス置換では、findコマンドの出力がwhileループに送信され、変数fnameが読み取られます。

_nname="${fname##*/}"_-パスからファイル名を抽出します

_"${fname%/*}"_-パスを抽出します

_"${nname//[[:space:]]/"_"}"_-ファイル名のスペースを_に置き換えます

_"${fname%/*}/${nname//[[:space:]]/"_"}"_-パス/新しいファイル名

3
user780735

bash(導関数とsh!ではわかりません)では、変数で 変数置換 などを使用できます

FILE="file name"
touch "$FILE"
mv -v "$FILE" "${FILE// /_/}"

ただし、これは少なくとも他のスペース文字(タブなど)を処理しません

0
Wilf

私のアプローチ:

find . -depth -name "* *" -execdir bash -c 'pwd; for f in "[email protected]"; do mv -nv "$f" "${f// /_}"; done' dummy {} +

読みやすさのための複数行バージョン:

find . -depth -name "* *" -execdir \
   bash -c '
      pwd
      for f in "[email protected]"; do
          mv -nv "$f" "${f// /_}"
      done
   ' dummy {} +

説明:

  • find . -name "* *"は、名前を変更する必要があるオブジェクトを検索します。注findはそのテストで非常に柔軟であるため、たとえばディレクトリのみの名前を変更したい場合は、find . -depth -type d -name "* *"で始めます。
  • -execdirは、オブジェクトがあるディレクトリで指定されたプロセス(bash)を実行するため、{}によって渡されるパスは、./barではなく常に./foo/barのようになります。つまり、パス全体を気にする必要はありません。欠点は、mv -vでパスが表示されないため、情報のためにpwdを追加しました(必要に応じて省略できます)。
  • bashでは、"${baz// /_}"構文を使用できます。
  • -depthは、次のことが起こらないようにします。findは、ディレクトリの名前を変更し(該当する場合)、そのコンテンツをoldパスで処理しようとします。
  • {} +は、bashmultipleオブジェクトをフィードできます({} \;構文とは異なります)。 for f in "[email protected]"で繰り返します。新しいプロセスの作成にはコストがかかるため、すべてのオブジェクトに対して個別のbashプロセスを実行しないことがポイントです。個別のmv- sを実行することは簡単に避けられないと思います。それでも、bash呼び出しの数を減らすことは、良い最適化のようです(pwdbashに組み込まれており、プロセスのコストはかかりません)。ただし、-execdir ... {} +は、異なるディレクトリのファイルを一緒に渡しません。 -exec ... {} +の代わりに-execdir ... {} +を使用することで、プロセスの数をさらに減らすことができますが、ファイル名だけでなくパスにも注意する必要があります( この他の回答 と比較してください)まともな仕事をするが while readはそれを遅くする )。これは、速度と(相対的な)単純さの問題です。 -execでの私の解決策は下にあります。
  • {}dummy内で$0になる直前のbash"[email protected]""$1" "$2" ...と同等であるため("$0" "$1" ...ではない)、このダミー引数が必要です。このようにして、{}によって渡されたすべてのものは後で"[email protected]"として利用できます。

より複雑でわずかに最適化されたバージョン( 別の回答 から取得したさまざまな${...}トリック):

find . -depth -name "* *" -exec \
   bash -c '
      for f in "[email protected]"; do
          n="${f##*/}"
          mv -nv "$f" "${f%/*}/${n// /_}"
      done
   ' dummy {} +

別の(実験的!)アプローチには vidir が含まれます。秘訣はvidir$EDITORを使用することですインタラクティブエディタではないかもしれません

find . -name "* *" | EDITOR='sed -i s/\d32/_/g' vidir -

警告:

  • これは、特殊文字(たとえば、改行)を含むファイル/ディレクトリ名に対して失敗します。
  • s/ /_/gを直接使用することはできません。\d32は回避策です。
  • vidirがどのように機能するかにより、数字またはタブを置き換えたい場合、アプローチはトリッキーになります。
  • ここで、vidirは、ファイル名(ベース名)だけでなくパスでも機能するため、ファイルのみ(つまり、ディレクトリではない)の名前を変更するのは難しい場合があります。

それにもかかわらず、あなたが何をしているのかを知っているなら、これは仕事をさらに速くするかもしれません。ただし、一般的なケースでは、vidirのこのような(絶対的な)使用はお勧めしません。この実験的アプローチが興味深いと感じたので、それを回答に含めました。

0