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
の実行を分けてしまうことでより簡易に明確に文字列をインジェクションできる
例えば上記で扱った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
で対応できるが…
youtube-dl
とかよりstreamlink
の方が一元的に利用できて良い