명명된 파이프를 사용하여 대화형 프로그램에 키 입력 보내기

명명된 파이프를 사용하여 대화형 프로그램에 키 입력 보내기

표준 입력의 키보드 명령을 통해 볼륨 제어와 같은 유용한 작업을 수행할 수 있는 대화형 모드가 있는 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실패(아마도 이 목적으로 스위치를 사용하여)하면 성공할 것입니다.

관련 정보