ファイル名の文字列を置き換えるためにfindとsedを使用するのが難しい

ファイル名の文字列を置き換えるためにfindとsedを使用するのが難しい

次のようなこの投稿注: エラーなしでfindand コマンドを実行できますが、ファイル名は同じままです。sed

服を脱がせようとしていますの発音_de_現在のディレクトリのすべてのmp3:

pronunciation_de_wählen.mp3
pronunciation_de_wange.mp3
pronunciation_de_weil.mp3
pronunciation_de_werden.mp3
pronunciation_de_zentrum.mp3

コマンドの問題を解決する前にクイックステータスチェック: find . -name "*.mp3"
現在のディレクトリのすべてのmp3を返します。これでこの部分がうまくいくことがわかりました。

sed --version返品sed (GNU sed) 4.4

私は走るfind . -name "*.mp3" -exec sed -i 's/pronunciation_de_//g' {} \;

何が起こっているのか完全に理解していることを確認するには、次の手順を実行します。

find .走る探す現在のディレクトリのコマンドです。
-name "*.mp3"すべての.mp3ファイル形式を返します。
-exec入力してコマンドを実行します。
sed -iこれ-私遷移とは、(一時的な)コピーではなく、実際のファイルで作業することを意味します。

のため's/old_word/new_word/g'

  • これSsedを代替モードに設定します。
  • /古い単語交換したい言葉です。
  • /新しい単語交換したい言葉です。私の例では空です。
  • / G最初の一致だけでなく、すべての一致に置換を適用します。

{}この文字列は、各反復中にファイル名に置き換えられます。
\;セミコロン終了探す注文する。バックスラッシュはセミコロン文字をエスケープし、シェルが文字通り解釈するのを防ぎます。

私はこの情報のほとんどをランダムなブログとStack Exchangeの投稿から入手します。

-exec オプションについてfind
findの-execコマンドで{} +はどういう意味ですか?

ほぼ確実に重複するこの質問を投稿する前に、時間をかけて実験して調査したいのですが、完全に詰まっています!

答え1

find -exec ...1行のシェルスクリプトを使用して交換を実行できます。

find . -name "*.mp3" -type f -exec bash -c 'mv "$1" "${1/pronunciation_de_}"' bash {} \;

ファイル名は実行中のbashプロセスにパラメータ{}として渡され、bashのパラメータ拡張機能が使用され、inが最初に表示される場合は空の文字列に置き換えられます。$1${1/pronunciation_de_}pronunciation_de_$1

追加オプションを使用すると、通常のファイルのみが一致する-type fことを確認できます。

答え2

pronunciation_de_名前で終わるすべてのファイルからプレフィックスを削除するには、名前が一致するファイルを検索して誤って.mp3pronunciation_de_*.mp3のファイル名を変更しないようにする必要があります(これが起こる可能性は低い)。

行中心のテキスト編集ツール(sedファイル名など)を使用しないでください。シェルは、ファイル名からプレフィックスとサフィックス文字列を効率的に削除する方法を知っています。

以下を使用してfind問題を解決できます。

find . -type f -name 'pronunciation_de_*.mp3' -exec sh -c '
    for pathname do
        newname=${pathname##*/}              # removes directory path, leaves filename
        newname=${newname#pronunciation_de_} # deletes the prefix string

        mv -i "$pathname" "${pathname%/*}/$newname"
    done' sh {} +

このコマンドは、転送されテストされたファイルfindのパス名を生成し、これらのファイルを一括して短いインラインスクリプトに供給します。-type-namesh -c

このスクリプトは与えられたパス名を繰り返し、各パス名の新しい名前を作成します。

  1. 初期ディレクトリパスを削除し、パス名を次のよう./some/path/pronunciation_de_werden.mp3に変更します。pronunciation_de_werden.mp3
  2. プレフィックス文字列を削除pronunciation_de_pronunciation_de_werden.mp3ますwerden.mp3

このコマンドは、元のmvファイルを元のディレクトリの新しい名前に移動し、元のファイル(元のパス${pathname%/*}名に展開されるディレクトリパス)の名前を変更します。

答え3

あなたの:

find . -name "*.mp3" -exec sed -i 's/pronunciation_de_//g' {} \;

ファイルの検索(次を含むすべてのタイプ定期的な目次シンボリックリンク先入選出...)、名前は現在のジョブ以下で終わり.mp3、各ファイルはプログラムと見つかったファイルを作業するファイルとして使用してsed内部モードで実行されます。s/pronunciation_de_//g

しかし、sedそれはsストリームeditorです。その使命は、テキストストリームを編集することです。ファイルを引数として与えると小川~であるコンテンツファイル名(名前ではありません)でsedファイル名は変更されません。ファイル名を変更するための標準コマンドはですmv。これには、特にバッチの名前を変更するためのいくつかのコマンドが含まれる場合があります(ファイルを検索して名前を編集する機能が組み込まれている可能性があります)。mmv、、、renamezmv

sedその名前をストリームとして指定すると、それを使用してファイル名を編集できますが、これは非常に面倒で確実に実行するのが難しい場合があります。

LC_ALL=C find . -depth -name 'pronunciation_de_*.mp3' -exec sh -c '
  ret=0
  for file do
    new_file=$(
      printf '%s\n' "$file" |
        sed "
          :1
          \$!{
            N
            b1
          }
          s|/pronunciation_de_\([^/]*\)\$|/\1|
        "
    )
    mv -i -- "$file" "$newfile" || ret=$?
  done
  exit "$ret"' sh {} +

(テストされていません)

次のことがどのように必要かをご覧ください。

  • LC_ALL=Cファイル名がロケールの文字エンコードでエンコードされない問題を回避します。
  • -depth葉を扱う前に枝を処理してください。
  • sedパイプ()を介して|ファイルパスを提供し、他のパイプ()を介して出力をシェル変数として収集できるようにシェルを実行します$(...)
  • 一度に1行だけを処理し、sedファイルパスを複数の行で構成できるため、sed置換を実行する前にパターンスペースにすべての行を累積するように指示する必要があります。
  • ファイルのデフォルト名のみが変更され、古いパスコンポーネントは変更されません。
  • -iこのオプションを使用すると、ユーザーにデータの損失を防ぐ機会を与えます。ただし、名前付きファイル./pronunciation_de_weil.mp3と名前付きディレクトリがある場合はまだ役に立ちません。./weil.mp3この場合、ファイル名は自動的に変更されます./weil.mp3/pronunciation_de_weil.mp3。 GNUの実装には、このような状況を軽減するオプションがmvあります。-T

zmv(シェルの自動ローディング機能)との比較zsh:

autoload zmv
zmv '(**/)pronunciation_de_(*.mp3)' '$1$2'

これには別の利点があります。

  • 実行する前に、潜在的な競合を確認してください。どの名前変更
  • 隠しファイルをスキップします(隠しファイルの名前も変更したい場合はそれを変更できますzmv '(**/)pronunciation_de_(*.mp3)(#qD)' '$1$2')。

1sed実装がこの非標準拡張をサポートし、次のパラメータがバックアップサフィックスと見なされないと仮定します。

答え4

バッチジョブの場合は、GNU Parallelを好みます。

ls -1 *.mp3 |
  sed 's/pronunciation_de_//' |
  parallel mv pronunciation_de_{} {}

sedファイル名からコンテンツを削除しましたpronunciation_de_。それでは、、、…{}のようになります。wählen.mp3wange.mp3

関連情報