ffmpeg
で気づいたこと
ffmpeg
では-headers
オプションを使えば複数のhttp header
を付与しつつ-i
で指定したurl
に向かってhttp
で叩けるが,複数の内容を利用する際には改行するための制御文字を間々で認識させる必要があるらしく,その場合は$'...'
で表せる.
そしてこの$'...'
については確かにzsh
のmanページでも取り扱い方法が記載されていた,以下を参照のこと.
man zshmisc | col -b | expand -t 4 | pcre2grep -Moe ' {0}(QUOTING\n)( {7,}(\S* *)*\S*\n*)*'
見た感じではprint
やprintf
はc++
の実装そのままで,対してecho
はzsh
用に作られた安全なものという印象を受けた.
zsh
で実験
準備
以下のシェルスクリプトを用いる
#!/bin/zsh -eu # this is testZsh4 echo "all arguments : ${*}" zparseopts -D -E -a optionArray -A optionPair test: if ((${+optionArray})); then for i in $optionArray; do echo "echo: component: ${i}" printf "printf: %s\n" $i done fi if ((${+optionPair})); then for key in ${(@k)optionPair}; do echo "echo: flags: ${key} => value: ${optionPair[$key]}" printf "printf: flags: %s => value: %s\n" $key $optionPair[$key] done fi echo "other arguments : ${*}"
-test
オプションにつける引数を変えれば処理の比較ができる
方針
改行文字を含めた文字列ab\ncd
を対象に色々と変えてみよう!
ab\ncd
% testZsh4 -test ab\ncd all arguments : -test abncd echo: component: -test printf: -test echo: component: abncd printf: abncd echo: flags: -test => value: abncd printf: flags: -test => value: abncd other arguments :
両者共に\
が消えた
'ab\ncd'
% testZsh4 -test 'ab\ncd' all arguments : -test ab cd echo: component: -test printf: -test echo: component: ab cd printf: ab\ncd echo: flags: -test => value: ab cd printf: flags: -test => value: ab\ncd other arguments :
echo
だけ改行文字が読まれた,printf
では文字として扱われた
"ab\ncd"
% testZsh4 -test "ab\ncd" all arguments : -test ab cd echo: component: -test printf: -test echo: component: ab cd printf: ab\ncd echo: flags: -test => value: ab cd printf: flags: -test => value: ab\ncd other arguments :
'ab\ncd'
と変わらない
$'ab\ncd'
% testZsh4 -test $'ab\ncd' all arguments : -test ab cd echo: component: -test printf: -test echo: component: ab cd printf: ab cd echo: flags: -test => value: ab cd printf: flags: -test => value: ab cd other arguments :
両者とも改行文字が読まれた
$"ab\ncd"
% testZsh4 -test $"ab\ncd" all arguments : -test $ab cd echo: component: -test printf: -test echo: component: $ab cd printf: $ab\ncd echo: flags: -test => value: $ab cd printf: flags: -test => value: $ab\ncd other arguments :
"..."
の動作はそのまま先頭に$
が入っただけだった
結論
printf
をみるにc++
系の実装なら$'...'
することでほぼ確実に制御文字を反映させられるっぽい,またecho
ではそれよりも簡単に制御文字を反映させられるっぽい
ffmpeg
での使いかた
-headers
オプションは多重の呼び出しが不可能である(2回目からは内容が置き換わる)ため,前述の手法で制御文字を有効にすることではじめて複数の内容を利用できる.とは言えその中で頻用される幾つかはffmpeg
側でも専用のオプションとして提供されており,本来ならばそういったものを利用するべきではないかとも考えられる(処理がめんどいって?それはそう).
詳細は以下で確認できる,-loglevel trace
で動作が全て標準出力される,-loglevel quiet
で何も表示されない,また-i [url]
を-headers [header]
より前に持ってくると-headers [header]
が認識されない(なぜかドキュメントにはのってないけど)
% ffmpeg \ -loglevel trace \ -headers $'Hoge: hoge\r\nHuga: huga' \ -i 'http://example.com/playlist.m3u8' \ -c copy \ output.mp4 ... User-Agent: Lavf/58.76.100 Accept: */* Range: bytes=0- Connection: close Host: example.com Icy-MetaData: 1 Hoge: hoge Huga: huga ...
以上の結果が得られればヘッダが正しく設定されたと言える(該当の動画は存在しないので最終的にはerror
が返される)
本来\r\n
はms-dosやwindowsで利用される作法であり,旧MacOSでは\r
のみ・現macOSでは\n
のみがそれぞれの「標準の改行コード」である,なので\n
だけで十分ではある…のだが心配なので\r\n
することを癖にしても良いかもしれない,実際の\r
はmacOSにおいて「同じ行の先頭まで戻る(そして出力が順に置き換わる)」動作を表すので余計な改行にはならないはず
おまけ
これ読めばわかると思われるが…?
QUOTING A character may be quoted (that is, made to stand for itself) by preceding it with a `\'. `\' followed by a newline is ignored. A string enclosed between `$'' and `'' is processed the same way as the string arguments of the print builtin, and the resulting string is considered to be entirely quoted. A literal `'' character can be included in the string by using the `\'' escape. All characters enclosed between a pair of single quotes ('') that is not preceded by a `$' are quoted. A single quote cannot appear within single quotes unless the option RC_QUOTES is set, in which case a pair of single quotes are turned into a single quote. For example, print '''' outputs nothing apart from a newline if RC_QUOTES is not set, but one single quote if it is set. Inside double quotes (""), parameter and command substitution occur, and `\' quotes the characters `\', ``', `"', `$', and the first character of $histchars (default `!').