標準入力のキーボードコマンドを使用して、ボリュームコントロールなどの便利な操作を実行できるインタラクティブモードを備えたmpg123プログラムがあります。 mpg123を起動して、名前付きパイプからコマンドを読み取ろうとします。これにより、他のプログラムとやり取りできます。
端末では、次のことを行います。
mkfifo pipe
tail -n1 -f pipe | mpg123 -vC /some/song.mp3
他の端末では、次のことを行います。
cat > pipe
-
-
今私は端末に座ってキーを押すのと同じようにこれがmpg123プログラムに送信されることを期待していますが-、そうではありません。誰かが私が間違っていることを教えてもらえますか?
ベストアンサー1
-C
これにより、mpg123が標準入力ではなく端末から読み取られるようです。しかし、私のmpg123のマニュアルページのバージョンでは、次のようなことがわかります。
-R, --remote
Activate generic control interface. mpg123 will then read and
execute commands from stdin. Basic usage is ``load <filename> ''
to play some file and the obvious ``pause'', ``command. ``jump
<frame>'' will jump/seek to a given point (MPEG frame number).
Issue ``help'' to get a full list of commands and syntax.
これがあなたが探しているものかもしれませんmpg123 -vR <pipe
。例の相互作用は次のとおりです(ボリュームは30%に設定されています)。
$ cat >pipe
load /some/song.mp3
volume 30
しかし、これにより、ターミナルの代わりに名前付きパイプに接続すると、古いモードがstdinからデータを読み取ることができなくなりますか-C
?-R
mpg123のソースコードを簡単に見てみると、端末からキーストロークを読み取るためにtermiosツールを使用していることがわかります。この
tcsetattr
ツールは、キーストロークが追加の処理なしでリーダーに送信される、いわゆる「非正規モード」に切り替えるために使用されます。 (特に、行全体が入力されるのを待つ必要はありません):
struct termios tio = *pattern;
(...)
tio.c_lflag &= ~(ICANON|ECHO);
(...)
return tcsetattr(0,TCSANOW,&tio);
(これは次のとおりです。GNU libcコードの例.)
次に、ループ内のファイル記述子0(stdin)に利用可能なデータがあることを確認し、その場合はそのデータからバイトを読み取るget_key
関数が呼び出されます()。しかし、ターミナルは機能しますが、パイプは機能しない理由をまだ説明していません!答えは端末初期化コードにあります。select
read(0,val,1)
/* initialze terminal */
void term_init(void)
{
debug("term_init");
term_enable = 0;
if(tcgetattr(0,&old_tio) < 0)
{
fprintf(stderr,"Can't get terminal attributes\n");
return;
}
if(term_setup(&old_tio) < 0)
{
fprintf(stderr,"Can't set terminal attributes\n");
return;
}
term_enable = 1;
}
tcgetattr
失敗またはterm_setup
失敗した場合は0にterm_enable
設定されます。 (ターミナルからキー押下を読み取る関数はで始まりますif(!term_enable) return 0;
。)実際にstdinが端末でない場合は
tcgetattr
失敗し、対応するエラーメッセージが表示され、キー押下処理コードはスキップされます。
$ mpg123 -C ~/input.mp3 <pipe
(...)
Can't get terminal attributes
これは、パイプを介してコマンドを送信しようとしてmpg123
-C
失敗する理由を説明します。これは実装者にとって議論の余地がある選択です。おそらく、キー入力処理コードの処理を無効にするのではなく、単に許可tcgetattr
/tcsetattr
失敗(おそらくこの目的のためにスイッチを使用して)するだけで成功します。