`zsh`で`eval`する

evalとは

       eval [ arg ... ]
          Read the arguments as input to the shell and execute the resulting
          command(s) in the current shell process.  The return status is the
          same as if the commands had been executed directly by the shell;
          if there are no args or they contain no commands (i.e. are an
          empty string or whitespace) the return status is zero.

要するに文字列を標準入力としてシェルに与えて実行(した上でその返り値を取得)できる

何が嬉しいのか

変数展開の都合によって通常の記法によるシェルスクリプトでは設定できないようなコマンドをそのまま通すことができる
もっと手軽に言えば,変数展開の実行とevalの実行を分けてしまうことでより簡易に明確に文字列をインジェクションできる

soluna-eureka.hatenablog.com

例えば上記で扱ったc++ likeな文字列の取り扱いについても,シェルスクリプトの文面に直接的にコマンドを書かなくとも

#!/bin/zsh -eu
# this is testZsh5

arg="ab\ncd"

echo "for echo():"

cmd1="echo ${arg}"
cmd2="echo '${arg}'"
cmd3="echo \"${arg}\""
cmd4="echo $'${arg}'"
cmd5="echo $\"${arg}\""

eval ${cmd1}
eval ${cmd2}
eval ${cmd3}
eval ${cmd4}
eval ${cmd5}

echo "for printf():"

cmd6="printf \"%s\n\" ${arg}"
cmd7="printf \"%s\n\" '${arg}'"
cmd8="printf \"%s\n\" \"${arg}\""
cmd9="printf \"%s\n\" $'${arg}'"
cmd10="printf \"%s\n\" $\"${arg}\""

eval ${cmd6}
eval ${cmd7}
eval ${cmd8}
eval ${cmd9}
eval ${cmd10}
% testZsh5 
for echo():
abncd
ab
cd
ab
cd
ab
cd
$ab
cd
for printf():
abncd
ab\ncd
ab\ncd
ab
cd
$ab\ncd

とすればより使い分けやすくなるし挙動がより確実に追跡できる,これと同じものを生で記述するのはかなり面倒になるだろう

curl to ffmpeg

悪用厳禁

インスペクタを開いてネットワークを監視しながら動画を見ていると,ほぼ必ずcurl形式のダウンロードリンクがブラウザにエイリアスとして提供されていることが見て取れるが,そのheader要素をそのままffmpegに渡すことでローカルファイルに落とせる,というのもCookieやsessionによって行われる管理を維持したままブラウザ環境とCLI環境に対応させることができる

しかしいくらそれをコピペしようがcurlにはffmpegのような機能はなく(もし単純にmp4が落ちてくるならまだしもhlsの配信が相手だと無力である),またffmpegとはそれ自身のコマンドはもちろん渡されるオプションのフォーマットも違う,それなら以下のように--ffmpeg [動画ファイルの名前]を末尾に追記するだけで自動的にオプションを加工して(-Hを集めて-headersに渡す)ffmpegを呼び出せる(確実に実行ファイルを指定する)ようにすれば,かなり楽だろうと思われる
現状ではちゃんと動作している

#!/bin/zsh -eu
# this is curl with ffmpeg

default=$argv
ffmpeg='--ffmpeg'

zparseopts -D -E -a optionArray -A optionPair -ffmpeg: X+: H+:

if ((${+optionPair[$ffmpeg]})); then
    echo "--ffmpeg option allowed!"
    n=0
    type=""
    head=""
    for i in $optionArray; do
        (( n += 1))
        if [ $i = "-X" ]; then
            echo "type added"
            type=$type$optionArray[n+1]'\r\n'
        elif [ $i = "-H" ]; then
            echo "head added"
            head=$head$optionArray[n+1]'\r\n'
        fi
    done
    command="/usr/local/bin/ffmpeg -loglevel quirt -headers $'${head}' -i '${*}' -c copy ${optionPair[$ffmpeg]}"
    eval "${command}"
else
    /usr/local/opt/bin/curl ${default}
fi

youtubeとかは

ffmpegだけでは無理なサイトもあるが,そういう時はstreamlinkの方が強いのでそっちに任せたい,しかしstreamlinkも決して万能ではなく対応していないサイトの方がむしろ多い,表向きに.m3u8.mp4が出てくるサイトならffmpegで対応できるが…

soluna-eureka.hatenablog.com

youtube-dlとかよりstreamlinkの方が一元的に利用できて良い

formulae.brew.sh