名前付きパイプを使用して対話型プログラムにキーストロークを送信する

名前付きパイプを使用して対話型プログラムにキーストロークを送信する

標準入力のキーボードコマンドを使用して、ボリュームコントロールなどの便利な操作を実行できるインタラクティブモードを備えた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関数が呼び出されます()。しかし、ターミナルは機能しますが、パイプは機能しない理由をまだ説明していません!答えは端末初期化コードにあります。selectread(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失敗(おそらくこの目的のためにスイッチを使用して)するだけで成功します。

おすすめ記事