複数ファイルのバッチ名を変更するためのシェルステートメント

複数ファイルのバッチ名を変更するためのシェルステートメント

私が探しています2行の名前を変更する私の音楽ライブラリを管理してみてください。

最初心配するファイル名。できるだけ簡単な名前を使いたいです。例%track %title.ext : 01 Song name.mp3 13 Song title.flacetc.私は現在のファイルの区切り記号(トラック番号と曲のタイトルの間)でハイフンを使用しますが、これは重複していると思います。

第二心配するフォルダ名、少し変えなければなりません。模様 From GENRE - Styles - ARTIST - Album (Year) to GENRE - Styles - ARTIST - Year Album (年の切り替えとアルバム部分も括弧省略)

(私はopenbsdを実行します。クッシュ 88.)

それは私が作った最も近い線です。ファイル名ケース: for f in * ; do mv "$f" "$(print "$f" | sed "s/ - / /")" ; done しかし、まだ動作していません。私はこれがコマンドの2番目の引数(ターゲット)を正しくカプセル化することに関連していると思いますmv編集する:引用符を追加すると$( ... )機能しますが、予期しませんでした)

$pwd 
/home/media/E - Chanson Française/CHANSON - Chanson Française - CHARLES TRENET - Le meilleur de Charles Trenet
$l -1
01 - Boum!.flac
02 - La route enchantée.flac
03 - Ah! Dis, Ah! Dis, Ah! Bonjour!.flac
04 - La vie qui va.flac
05 - Quand j'etais p'tit.flac
06 - Ménilmontant.flac
07 - Tout me sourit.flac
08 - Le oiseaux de Paris.flac
...
$for f in * ; do mv "$f" "$(print "$f" | sed 's/ - / /')" ; done
$l -1
01 Boum!.flac
02 La route enchantée.flac
03 Ah! Dis, Ah! Dis, Ah! Bonjour!.flac
04 La vie qui va.flac
05 Quand j'etais p'tit.flac
06 Ménilmontant.flac
07 Tout me sourit.flac
08 Le oiseaux de Paris.flac
...

二重引用符を入れ子にするとエラーが発生すると思いましたが、うまくいきます。これで最初の事件は解決された。

これフォルダ名その事件は私をさらに避けた。以下は、変更する名前の例です。

$ ls -1
...
ELECTRO - Cyberpunk - CARPENTER BRUT - Blood Machines (2020)
ELECTRO - Cyberpunk - CARPENTER BRUT - Leather Teeth (2018)
ELECTRO - Cyberpunk - CARPENTER BRUT - Leather Terror (2022)
ELECTRO - Cyberpunk - CARPENTER BRUT - Trilogy (2015)
...
REGGAE - Roots - GROUNDATION - Each One Teach One (2001)
REGGAE - Roots - GROUNDATION - Hebron Gate (2002)
REGGAE - Roots - GROUNDATION - Upon the Bridge (2006)
REGGAE - Roots - GROUNDATION - Young Tree (1999)
...

結果は次のようになります。

$ ls -1
...
ELECTRO - Cyberpunk - CARPENTER BRUT - 2015 Trilogy
ELECTRO - Cyberpunk - CARPENTER BRUT - 2018 Leather Teeth
ELECTRO - Cyberpunk - CARPENTER BRUT - 2020 Blood Machines
ELECTRO - Cyberpunk - CARPENTER BRUT - 2022 Leather Terror
...
REGGAE - Roots - GROUNDATION - 1999 Young Tree
REGGAE - Roots - GROUNDATION - 2001 Each One Teach One
REGGAE - Roots - GROUNDATION - 2002 Hebron Gate
REGGAE - Roots - GROUNDATION - 2006 Upon the Bridge
...

フィールドを切り替えるには、awkを使用する必要があるようです。for f in *CARPENTER\ BRUT* ; do mv "$f" "$( print "$f" | awk ... )" ; done最後のハイフンの次の年をawkに切り替えて、 trで角かっこを削除することもできますが、それを学ぶのに苦労しています。

答え1

zshをインストールできる場合:

  • XX - title.flac一般的なファイルにXX title.flac

    zsh <<\EOF
      autoload zmv
      zmv -n '(**/)(<-> )- (*.(#i)(ogg|mp3|flac))(#q.)' '$1$2$3' < /dev/tty
    EOF
    
  • GENRE - Styles - ARTIST - Album (Year)GENRE - Styles - ARTIST - Year Albumディレクトリへ

    zsh <<\EOF
      autoload zmv
      zmv -n '(**/)(* - * - * - )(*) \((<->)\)(#q/)' '$1$2$4 $3' < /dev/tty
    EOF
    

満足すれば削除-n(テスト実行)します。

zsh をインストールできない場合findand を使用するperlと、次のような結果が得られます。

  • XX - title.flacXX title.flac一般ファイルとして

    LC_ALL=C find . -depth -name '[0-9]*.*' -type f -print0 |
      perl -l -0ne '
        ($dir, $base) =  m{^(.*/)(.*)\z}s;
        if ($base =~ s/^(\d+ )- (.*\.(?i:ogg|mp3|flac))\z/$1$2/s) {
          print qq(rename($_, "$dir$base")) or warn "$_: $!";
        }'
    
  • GENRE - Styles - ARTIST - Album (Year)GENRE - Styles - ARTIST - Year Albumディレクトリへ

    LC_ALL=C find . -depth -name '*(*)' -type d -print0 |
      perl -l -0ne '
        ($dir, $base) =  m{^(.*/)(.*)\z}s;
        if ($base =~ s/( - .* - .* - )(.*) \((\d+)\)\z/$1$3 $2/is) {
          print qq(rename($_, "$dir$base")) or warn "$_: $!";
        }'
    

そして、満足のprint qq(...) いくものを削除してください。rename()

しかし、注目すべき点は次のとおりです。

  • また、隠しファイル/ディレクトリ(および隠しディレクトリ内)も処理します。
  • 保護機能がないため、zmv最終的に既存のファイルを上書きできます。

OpenBSDのkshユーティリティとネイティブPOSIXユーティリティを使用してこれを実行することは可能ですが、非常に不快です。

可能:

  • XX - title.flac一般的なファイルにXX title.flac

    LC_ALL=C find . -depth -name '[0-9][0-9] - *' '(' \
      -name '*.[Ff][Ll][Aa][Cc]' -o \
      -name '*.[Oo][Gg][Gg]' -o \
      -name '*.[Mm][Pp]3' ')' -type f -exec ksh -c '
      for file do
        dir=${file%/*} base=${file##*/}
        print -r mv -i -- "$file" "$dir/${base%% *}${base#* -}"
      done' {} +
    
  • GENRE - Styles - ARTIST - Album (Year)GENRE - Styles - ARTIST - Year Albumディレクトリへ

    LC_ALL=C find . -depth -name '* - * - * - * (*[0-9])' -type d -exec ksh -c '
      for file do
        dir=${file%/*} base=${file##*/}
        if [[ $base = *" ("+([0-9])")" ]]; then
          album="${base##* - }"
          year=${album##*\(}
          year=${year%\)}
          base=${base%"$album"}
          album=${album%" ("*}
          print -r mv -i -- "$file" "$dir/$base$year $album"
        fi
      done' {} +
    

(満足したら削除してくださいprint -r)。

その方法とperl同じ注意がありますが、-i渡されたオプションはデータの損失を防ぐmvのに役立ちます(代わりにmv移動する到着引っ越すターゲットファイルが存在し、ディレクトリタイプの場合)。


あなたの試みに関して:

  • sedこれはテキストユーティリティであり、行ベースであり、ファイルパスに単一のテキスト行だけでなくテキストも含まれるという保証はないため、ファイル名へのファイルパスを処理しないことが最善です。
  • print、基本的にオプションを受け入れる多くの実装と同様にecho(OpenBSDのksh実装ではそうではないようですが、一部は任意のコマンドを実行できます)、いくつかのバックスラッシュエスケープシーケンス拡張を実行します。テキストを逐語的に出力するには(有効な行で終わるように改行文字の後に)、特に始まらないことを保証できない場合は、またはがprint -r - "$text"必要です。print -r -- "$text"$text-
  • コマンド()を引用符なしで置き換えると、$(...)結果に最終的に分割+globが適用されます。はい、引用してください。ネストされた参照は、廃止されたコマンド置換形式を使用している場合にのみ問題になりますが`...`、その場合でも可能ですcmd1 "`other-cmd \" $var \"`"。 。
  • $(...)削除に注意してくださいみんな末尾の改行により、通常、あまりにも多くの項目が削除されます。
  • --mvそれから彼は消えた。
  • mvsedファイルパスを変更しなくても呼び出しになります。
  • OpenBSDのkshでfor i in *現在の作業ディレクトリに隠されていないファイルがない場合、ループはファイル名の*パスを残します。一致しないファイルに関するエラーが報告さzshれます。zmv
  • oksh globを使用している場合は、ファイルの種類(zshの(#q.)===-type f(#q/)===-type dなど)に応じてglob拡張を制限することはできません。
  • 上記の方法とは異なり、現在の作業ディレクトリのファイル名のみを変更するため、各ディレクトリでプロセスを繰り返す必要があります。

関連情報