お知らせ

  • 利用規約を守って投稿してください。また、よくある質問および投稿の手引きも参照してください。
  • メッセージの投稿にはアカウントが必要です。未登録の方は、ユーザ登録ページからアカウントを作成することができます。

#1 2014-01-10 23:59:39

dd
メンバ
登録日: 2014-01-05

flacファイルの名前をタグ情報を元に変更したい

現在、音楽ファイルをflac形式で保存しています。アーティスト名でフォルダを作り、その下の階層にアルバム名でフォルダを作ってファイルを入れています。
ファイルの名前を、タグ情報を引用して[Artist] - [Album] - [Track Number].[Title]という形式にしたいと考えています。今、flacコマンドを使用するためにインストールし、様々なHPを参考に以下のコードを作成しました。

コード:

for a in *.flac;do
ARTIST=`metaflac "$a" --show-tag=ARTIST | sed s/.*=//g`
ALBUM=`metaflac "$a" --show-tag=ALBUM | sed s/.*=//g`
TITLE=`metaflac "$a" --show-tag=TITLE | sed s/.*=//g`
TRACKNUMBER=`metaflac "$a" --show-tag=TRACKNUMBER | sed s/.*=//g`
mv "$a" "$ARTIST - $ALBUM - `printf %02g $TRACKNUMBER`.$TITLE.flac";
done

上記のコードを実行すれば、カレントディレクトリ内のフォルダは希望通りにリネームできました。しかし、これを200以上のフォルダにcdコマンドで移動しながら実行するというのは骨が折れます。
そこで良いコードを考えていただけないでしょうか。おそらくフリーのソフトウェアで便利なものもたくさんあるとは思いますが、ターミナルの練習としてコードでやろうと考えています。
findコマンドを使うことでうまく行くかと考えたのですが、xargsコマンドを用いても引数の受け渡しの部分で詰まってしまいました。

オフライン

 

#2 2014-01-11 03:22:38

si
メンバ
From: hokkaido kitami, jp
登録日: 2007-01-15

Re: flacファイルの名前をタグ情報を元に変更したい

難しいコマンドを使わなくとも、わかる範囲のコマンドで、作られたほうが良いのではないですか?
単純に考え、
アーティスト名のディレクトリが入っているディレクトリで、ディレクトリを取り、順に、作ってあるリネーム処理をし、ディレクトリを移動していけば良いのではないでしょうか?
簡単に作れば、for の2重ループ構造でもいいでしょうし、リネーム処理コード部分を、関数にして、ディレクトリ移動処理ループ内から呼び出しても良いでしょう。
注意するとすれば、カレントディレクトリと上位ディレクトリを表す、”.”と”..”で処理をしないことくらいでしょうか?

オフライン

 

#3 2014-01-11 03:41:14

si
メンバ
From: hokkaido kitami, jp
登録日: 2007-01-15

Re: flacファイルの名前をタグ情報を元に変更したい

si による投稿:

注意するとすれば、カレントディレクトリと上位ディレクトリを表す、”.”と”..”で処理をしないことくらいでしょうか?

for x in *
do
  echo $x
done

で確認したら、”.”と”..” は、出てきませんでしたね。
失礼

オフライン

 

#4 2014-01-11 16:18:16

dd
メンバ
登録日: 2014-01-05

Re: flacファイルの名前をタグ情報を元に変更したい

siさん、回答ありがとうございます。実は投稿の後にOSの情報を書き忘れたことに気づきました。ubuntu13.10を使用しています。
どうも正規表現のあたりでうまく行かなくて諦めかけていました。アドバイスを参考に以下のコードを書いたのですが、やはりうまく行きません。

コード:

for a in $(ls -F | grep /)
do
    `cd "$a"`
    for b in $(ls -F | grep /)
    do
        `cd "$b"`
        for c in *.flac
        do
            ARTIST=`metaflac "$c" --show-tag=ARTIST | sed s/.*=//g`
            ALBUM=`metaflac "$c" --show-tag=ALBUM | sed s/.*=//g`
            TITLE=`metaflac "$c" --show-tag=TITLE | sed s/.*=//g`
            TRACKNUMBER=`metaflac "$c" --show-tag=TRACKNUMBER | sed s/.*=//g`
            mv "$c" "$ARTIST - $ALBUM - `printf %02g $TRACKNUMBER`.$TITLE.flac"
        done
    done
done

出力結果は以下のようになります。とても長いので一部抜粋です。

コード:

bash: cd: THE: そのようなファイルやディレクトリはありません
*.flac: ERROR: reading metadata, status = "FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE"

The FLAC file could not be opened.  Most likely the file does not exist
or is not readable.
*.flac: ERROR: reading metadata, status = "FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE"

The FLAC file could not be opened.  Most likely the file does not exist
or is not readable.
*.flac: ERROR: reading metadata, status = "FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE"

きりがないので途中で実行を止めると、カレントディレクトリはコマンドを実行したディレクトリのままです。
THEというディレクトリがないこと、cdコマンドがTHEというディレクトリを見つけられずにエラーになっていることから、変数が空白ごとに別々に読み込まれていることが原因のエラーと考えました。
様々なHPを参考に上記のようにバッククォーテーションを用いて見たのですが症状は変わらず。リストコマンドを単純に*で置き換えてもダメでした。

もう少しヒントをいただけないでしょうか。

オフライン

 

#5 2014-01-11 17:31:32

si
メンバ
From: hokkaido kitami, jp
登録日: 2007-01-15

Re: flacファイルの名前をタグ情報を元に変更したい

コード:

for a in $(ls -F | grep /)
do
    `cd "$a"` ---> これに対応する、cd .. が無い
    for b in $(ls -F | grep /) ---> このループは要るの?
    do
        `cd "$b"` ---> これもまた対応する、cd .. が無い
        for c in *.flac
        do
            ARTIST=`metaflac "$c" --show-tag=ARTIST | sed s/.*=//g`
            ALBUM=`metaflac "$c" --show-tag=ALBUM | sed s/.*=//g`
            TITLE=`metaflac "$c" --show-tag=TITLE | sed s/.*=//g`
            TRACKNUMBER=`metaflac "$c" --show-tag=TRACKNUMBER | sed s/.*=//g`
            mv "$c" "$ARTIST - $ALBUM - `printf %02g $TRACKNUMBER`.$TITLE.flac"
        done
    done
done

オフライン

 

#6 2014-01-11 20:18:41

si
メンバ
From: hokkaido kitami, jp
登録日: 2007-01-15

Re: flacファイルの名前をタグ情報を元に変更したい

2重目のループ要るのかなと思いましたが、
ディレクトリ構成が
 アーチスト ー アルバム ー 曲
だから、3重のループで良いのですね。

オフライン

 

#7 2014-01-12 00:58:30

dd
メンバ
登録日: 2014-01-05

Re: flacファイルの名前をタグ情報を元に変更したい

siさん、何度も回答ありがとうございます。実は最初にアドバイスを頂いた際に、cdコマンドで上の階層に戻るようにコードを書いてみました。いろいろ試行錯誤の末、cd ..はないほうがいいのではないかとも考えていましたが、今考えなおすとご指摘通りないとだめですね。
改めて改善したコードが以下です。まだ問題点があります。

コード:

for a in $(ls -F | grep /)
do
    `cd "$a"`
    for b in $(ls -F | grep /)
    do
        `cd "$b"`
        for c in *.flac
        do
            ARTIST=`metaflac "$c" --show-tag=ARTIST | sed s/.*=//g`
            ALBUM=`metaflac "$c" --show-tag=ALBUM | sed s/.*=//g`
            TITLE=`metaflac "$c" --show-tag=TITLE | sed s/.*=//g`
            TRACKNUMBER=`metaflac "$c" --show-tag=TRACKNUMBER | sed s/.*=//g`
            mv "$c" "$ARTIST - $ALBUM - `printf %02g $TRACKNUMBER`.$TITLE.flac"
        done
    cd ..
    done
    cd ..
done

これを実行すると、また大量に印字されるので途中で実行を中止するとホームディレクリにいました。この現象から想像するに、cd $aコマンドやcd $bがうまく実行されず、cd ..コマンドだけが実行されていると考えられます。
なぜcd $aなどのコマンドがうまくいかないかを考えてみました。自分の至る結論はやはり空白ごとに区切って引数になっているということです。少し状況の説明が不足していたので以下に詳細を書きます。

実行結果のログを見ると、"The"というディレクトリに移動しようとして、そのようなディレクトリがないとエラーが返されています。これは、"The Beatles"というアーティスト名のディレクトリがあり、それを変数aとしてcdコマンドの引数とする際に、cd The とcd Beatlesというように2つのコマンドに別れてしまっていることが原因と考えました。

この現象を防ぐためにバッククォーテーションを使ってみたのですが改善されません。もしこのコードの問題点が指摘した部分であれば、正しい表現をアドバイスいただければと思います。
もしその他にも問題点がありましたら、そのご指摘もしていただければと思います。

オフライン

 

#8 2014-01-12 02:13:32

STGSAGWAN
ゲスト

Re: flacファイルの名前をタグ情報を元に変更したい

こんな感じかな?

コード:

find '/path/to/files' -type f -name '*.flac' | while read f
do
    n=変更後ファイル名
    d=$(dirname "$f")
    mv -v "$f" "$d/$n"
done
 

#9 2014-01-12 03:21:32

dd
メンバ
登録日: 2014-01-05

Re: flacファイルの名前をタグ情報を元に変更したい

STGSAGWANさん、回答ありがとうございます。参考に、というよりもほとんどそのまま自分の環境に当てはめて実行してみました。

コード:

find . -type f -name '*.flac' | while read f
     do
    ARTIST=`metaflac "$f" --show-tag=ARTIST | sed s/.*=//g`
        ALBUM=`metaflac "$f" --show-tag=ALBUM | sed s/.*=//g`
        TITLE=`metaflac "$f" --show-tag=TITLE | sed s/.*=//g`
        TRACKNUMBER=`metaflac "$f" --show-tag=TRACKNUMBER | sed s/.*=//g`
    d=$(dirname "$f")
        mv "$f" "$d/$ARTIST - $ALBUM - $TRACKNUMBER.$TITLE.flac"
     done

for文でうまく行かなかった理由が未だわからないままですが、while文にすることでうまく行ったようです。本当に回答ありがとうございました。満足行く結果が得られました。

ここまでで十分なのですが、実はSTGSAGWANさんの回答を参考にしている際に、間違えて変数dなしで実行してしまいました。結果、見事にカレントディレクトリに希望通りのファイル名にリネームされたファイルの数々が作られました。mvコマンドをよく理解していなかったからですね。いくつかカレントディレクトリに移動されていないファイルもあるのでそれがよく分からない点ですが、今後理解していこうと思います。また、間違えて移動してしまったファイルを元のディレクトリに戻すコードも考えてみます。もしこれを見かけたかたで良い案があれば意見いただければとも考えていますが、まだ試行錯誤もしていない段階なので、問題が起きたらまた質問させていただきます。今回はsiさん、STGSAGWANさんともにありがとうございました。

オフライン

 

#10 2014-01-12 13:47:56

katsu07
ゲスト

Re: flacファイルの名前をタグ情報を元に変更したい

for文でうまく行かなかった理由が未だわからないままですが、

#7でご自身で答えを出していますが、スペース混じりのデータにfor文を使うと、IFS(インターナルフィールドセパレーター:区切り文字)を変更しなければなりません。
スペースが区切り文字として認識されてしまい、"aaaa bbbb"の様に1つとして認識させたい物が"aaaa"と"bbbb"の様に2つに認識されてしまう為です。

カレントディレクトリに希望通りのファイル名にリネームされたファイルの数々が作られました。

パスが、アーチスト/アルバム と言う構成との事ですが、flacファイルに埋め込まれているアーチストとアルバム情報が「パスと全く同じ文字構成」で書き込まれているならば、同じ様にそこから情報を取得してパス名を作り出せば良いのではないでしょうか。

mv "カレントにあるflacファイル" "${ARTIST}/${ALBUM}"

といった感じ。
findはカレントディレクトリのみ検索させる為に

find . -maxdepth 1 -name "*.flac" -type f

の様にすれば良いかと思います。
始めは mv を echo に変えて画面上の出力だけで確認し、それが正しいと判断できたら mv に変更する方が被害が出ないと思います。

 

#11 2014-01-12 19:25:50

si
メンバ
From: hokkaido kitami, jp
登録日: 2007-01-15

Re: flacファイルの名前をタグ情報を元に変更したい

dd による投稿:

自分の至る結論はやはり空白ごとに区切って引数になっているということです。

空白文字は、デリミタになるので
for a in $(ls -F | grep /)
等とすると、word 単位に分割されてしまします。
こういった場合の、回避策の、1例です

コード:

#!/bin/bash

for a in *
do
  if test -d "$a"
  then
    cd "$a"
    pwd
    cd ".."
  fi
done

オフライン

 

#12 2014-01-12 19:38:00

si
メンバ
From: hokkaido kitami, jp
登録日: 2007-01-15

Re: flacファイルの名前をタグ情報を元に変更したい

dd による投稿:

また、間違えて移動してしまったファイルを元のディレクトリに戻すコードも考えてみます。

ここまで来ると、多分、シェルスクリプトだけでは、シンドイと思われますので、文字列処理ライブラリの豊富なスクリプト言語、
例えば、perl, ruby, scheme, python 等を、覚えてトライしたほうが良いかも知れません。

オフライン

 

#13 2014-01-12 22:21:49

dd
メンバ
登録日: 2014-01-05

Re: flacファイルの名前をタグ情報を元に変更したい

katsu07さん、siさん回答ありがとうございます。最初に結論から書くと、全てうまく行きました。回答して下さった皆さんは、自分でコードを書きたいというわがままに答える形でヒントのみを与えて下さり、物分かりの悪い自分にイライラしていたかもしれませんがようやく解決です。

今後同じ問題にぶつかった方のためにも、備忘録としても書き込みを頂いてからの試行錯誤を記載しておきます。まずkatsu07さんの書き込みを見て良い案だと思いました。しかし問題もありました。flacファイルに情報をタグ付けした際に、データベースの情報を利用するとcdによって同じアーティストでも大文字小文字等の表記が異なる場合があり、自分でディレクトリを作り統一するという作業をしていました。そのためタグの情報とディレクトリ名が少し異なるファイルがいくつかありました。そのためechoコマンドを使うというアドバイスは大いに活用させていただくとして、他の戦略をとることにしました。

siさんの書き込みを見て、諦めかけましたが、なんとか実現出来ました。挙げていた言語だとruby、schemeを齧ったことがありましたが、本当に触りだけなので自信がありませんでした。しかしターミナル上でできる自信はありました笑。一度ディレクトリを全て削除し、タグの情報を元にディレクトリを作り直し、移動するという手順をとりました。ディレクトリの削除はGUIで行い、ディレクトリの作成、移動は以下のコードで行いました。

コード:

find . -type f -name '*.flac' | while read f;
do
    ARTIST=`metaflac "$f" --show-tag=albumartist|sed s/.*=//g`
    ALBUM=`metaflac "$f" --show-tag=album | sed s/.*=//g`
    mkdir -p "$ARTIST"/"$ALBUM"
done

find . -maxdepth 1 -name "*.flac" -type f | while read f;
do
    ARTIST=`metaflac "$f" --show-tag=albumartist|sed s/.*=//g`
    ALBUM=`metaflac "$f" --show-tag=album | sed s/.*=//g`
    mv "$f" "$ARTIST"/"$ALBUM"
done

まとめて一つのwhile文にできますが、うまく行くか少し不安でこのような形にしました。このコードを作るまでにechoを使う手法で何度か確認もしました。結果は大成功でした。今回はsiさんをはじめ多くの方に助けていただき、希望通りのリネーム及びターミナル上でのファイル、ディレクトリの扱いに慣れることができました。本当にありがとうございました。

オフライン

 

Board footer

Powered by FluxBB