zip内のファイルを片っ端からmplayerに送るシェルスクリプト書いた

前書き

本当はmplayerでzip内のファイルを再生できるようにpatchを書こうと
ソースコードを眺めていたが面倒くさくなってシェルでなら前から再生できてたし
シェルスクリプトで書いたらなんかもう満足した
気が向いたらpatch書く
デメリットはcacheの領域超えたら再生できないこととか再生時間がどれだけあるかわからないとか色々ある
そういうわけなんで名前付きパイプなんて使わずにram disk上にファイル作成した方がいいと思います

本編と解説 (最初の2行以降は読まなくていいです)

https://raw2.github.com/silenvx/bin/master/z2m.sh
ここに置いてある。zipファイルを引数にして使う

短いとアレなんでシェルスクリプト書けない人のために何やってるか書くほどではないが書く
もしかしたら嘘書いているかもしれない

この記事書いた時のソースコード全体

#!/bin/sh
# zipの中にあるファイルを片っ端からmplayerに渡すプログラム

if [ -f "$1" ];then
    pipe=`mktemp -u`
    trap "rm \"${pipe}\";exit 1" 1 2 3 9 15

    mkfifo "${pipe}"||{ echo 'error: mkfifo';exit 1; }
    IFS=$'\n'
    for zipInFile in `zipinfo -1 "${1}"|sed -e 's/\[/\\\\\[/g' -e 's/\]/\\\\\]/g'` ;do
        echo " --- staring: ${zipInFile}"
        unzip -p "${1}" "${zipInFile}" > "${pipe}" &
        mplayer "${pipe}"
    done
    rm "${pipe}"
else
    echo "not found: $1"
    exit 1
fi
      1 #!/bin/sh

スクリプトの1行目はどこそこに置いてあるプログラムの引数として実行しますって意味
この場合/bin/sh z2m.shとして実行される
#!がマジックナンバー

      2 # zipの中にあるファイルを片っ端からmplayerに渡すプログラム

ただのコメント

      4 if [ -f "$1" ];then
     ()
     16 else
     17     echo "not found: $1"
     18     exit 1
     19 fi

ファイルが存在してるかどうか判定してる
なかったら何もできないのでエラー表示して終了
ifは引数に書いてるコマンドが0かそれ以外か見てる。0ならthen、それ以外ならelseに飛ぶ
[に-fオプションをつけるとその後ろにあるファイル名が存在するかどうかで戻り値を変える、あれば0
変数に使ってる$1はシェルスクリプトに使われた第1引数が入ってる
この場合 z2m.sh hoge.zipとかって使われることを想定しているからhoge.zipが入ってる
exitはプログラムの終了、その引数の数字はシェルスクリプト自体の戻り値、1は基本的にはエラーに使う

      5     pipe=`mktemp -u`

pipe変数にmktempコマンドの標準出力を入れてる
``で囲うことで中身のコマンドの標準出力に置き換えることができる
mktempは一時ファイルを作成するコマンド、-uオプションをつけると作った振りをして他とかぶらない名前だけ標準出力される
作ったファイルが消せなくなると困るのでpipe変数に入れてます

      6     trap "rm \"${pipe}\";exit 1" 1 2 3 9 15

Ctrl+Cとかされて途中終了されてしまうとゴミファイルが残ってしまうのでそういうコマンドを感知したら
プログラムが終了する前に消すように命じてる
trapの第1引数は実行するコマンド、第2引数以降はシグナルを指定する
シグナルってのはkillコマンドでプログラムに送るアレ
それぞれの数字の意味は各自調べてください、覚えてないです
rmは引数にあるファイルの削除

      8     mkfifo "${pipe}"||{ echo 'error: mkfifo';exit 1; }

名前付きパイプを作成して、失敗したらエラー表示して終了してる
mkfifoは名前付きパイプっていうファイルを作成できる
これは普通のパイプのファイル版と思ってもらっていい
ファイルのようにパイプが使えるけど何で直接mplayerに渡さないかというとそうするとCUIでのキー操作を受け付けなくなるから
途中に書いてる||はmkfifoの戻り値が0以外だったら次に書いてるコマンドを実行してくれって意味
echoは引数に書いてる文字列の標準出力を行う
これまた途中に書いてる;は次に実行するコマンドを1行で書く時に間に挟む
なんで{}で囲ってるかというと、どっかで||の後ろは1つしかコマンドが実行されないとかどっかで見た気がするから
こうすることで1つまとめにできる

      9     IFS=$'\n'
     10     for zipInFile in `zipinfo -1 "${1}"|sed -e 's/\[/\\\\\[/g' -e 's/\]/\\\\\]/g'` ;do
    ()
     14     done

IFS変数は区切り文字を入れるとforなどで勝手にその文字で区切って別けてくれる
ここでは改行だけ区切り文字にしたいから$'\n'を代入してる、この文字列で改行を指定できる
forは繰り返しを行いたい時に書く
第1引数に第2引数から得た文字列をIFS変数を参考に区切ってループしていく
全部区切り終えたらループからは脱出する
zipinfoは引数に指定されたzipファイルの情報を出力するプログラム
オプションで-1を指定するとファイル名が1行ずつ表示される
これをsedっていう置換プログラムに送ってる
この後使うunzipは[や]の文字が正規表現として扱われてしまうのでエスケープするようにしてる
sedの-eオプションはこの後正規表現を書きますよという意味
''で囲まれてる文字列は、そのままの意味なんで勝手に解釈しないでくれって意味
ようはエスケープじゃないしスペースは引数の区切り文字じゃないよって言ってる
最初に書かれてるsは置換します
その後の/はこれから書く時は区切り文字は/ですって言ってる
\[は置換前の文字で[が正規表現に使われてるので\を使ってエスケープしてる
\\\\\[は置換後の文字で\も書きたいならエスケープする必要があるので\\と書いてる、ようは\\[って書いてあって
\が1個多いのは変数の中身を出す時も勝手にエスケープされちゃうから1個多く書いてる
最後のgは対象の文字列は全てs(置換)するという意味
その次の-e以降も同じ
最後に書いてある;doとdoneはfor文はdoから始まってdoneで終わる必要があるから書いてある

     11         echo " --- staring: ${zipInFile}"

どのファイルを解凍して再生するかわかるように出力してる

     12         unzip -p "${1}" "${zipInFile}" > "${pipe}" &

unzipに-pオプションを足すと標準出力に解凍するファイルが出力される
1つ目の引数は対象のzipファイル
2つ目の引数はそのzipファイルの中身のpathを指定して、解凍するファイルを選んでる
その後に書いてる>は標準出力を書き込むためのものでその後に書いてる名前付きパイプに上書きしている
最後の&はバックグラウンドで実行している、つまり終了を待たずに次にコマンドに以降できる

     13         mplayer "${pipe}"

名前付きパイプをmplayerで再生してる

    15     rm "${pipe}"

正常終了前にちゃんと消しておく