[unix] 명령 행 프로그램이 출력이 재 지정되는 것을 막을 수 있습니까?

나는 이것을하는 데 너무 익숙해졌습니다.
someprogram >output.file

프로그램이 생성하는 출력을 파일에 저장하려고 할 때마다 수행합니다. 또한이 IO 리디렉션 의 두 가지 변형을 알고 있습니다 .

  • someprogram 2>output.of.stderr.file (stderr 용)
  • someprogram &>output.stderr.and.stdout.file (stdout + stderr 겸용)

오늘 나는 불가능하다고 생각한 상황을 겪었습니다. 다음 명령을 사용하고 xinput test 10예상대로 다음과 같은 결과가 나타납니다.

user @ hostname : ~ $ xinput 테스트 10
키 프레스 30
키 릴리스 30
키 프레스 40
키 릴리스 40
키 누름 32
키 릴리스 32
키 누름 65
키 릴리스 65
키 누름 61
키 릴리스 61
키 누름 31
^ C
user @ hostname : ~ $

이 출력은 평소처럼을 사용하여 파일에 저장할 수있을 것으로 기대했습니다 xinput test 10 > output.file. 그러나 내 기대와 달리 파일 output.file은 비어 있습니다. 이것은 xinput test 10 &> output.filestdout 또는 stderr에서 무언가를 놓치지 않도록하기 위해서도 마찬가지입니다 .

나는 정말로 혼란 스러우므로 xinput프로그램이 출력을 리디렉션하지 않는 방법이 있는지 물어보십시오 .

최신 정보

나는 출처를 보았다. 이 코드에 의해 출력이 생성되는 것 같습니다 (아래 스 니펫 참조). 출력이 일반 printf에 의해 생성되는 것처럼 보입니다.

// 파일 test.c에서

static void print_events (디스플레이 * dpy)
{
    XEvent 이벤트;

    while (1) {
    XNextEvent (dpy, & Event);

    // [... 다른 이벤트 유형은 여기에서 생략됩니다 ...]

        if ((Event.type == key_press_type) ||
           (Event.type == key_release_type) {
        int 루프;
        XDeviceKeyEvent * key = (XDeviceKeyEvent *) & Event;

        printf ( "key % s % d", (Event.type == key_release_type)? "release": "press", 키-> 키 코드);

        for (loop = 0; loopaxes_count; 루프 ++) {
        printf ( "a [% d] = % d", 키-> first_axis + 루프, 키-> axis_data [loop]);
        }
        printf ( "\ n");
    }
    }
}

소스를 이것으로 수정했습니다 (아래 스 니펫 참조). stderr에 출력 사본을 가질 수 있습니다. 이 출력은 리디렉션 할 수 있습니다.

 // 파일 test.c에서

static void print_events (디스플레이 * dpy)
{
    XEvent 이벤트;

    while (1) {
    XNextEvent (dpy, & Event);

    // [... 다른 이벤트 유형은 여기에서 생략됩니다 ...]

        if ((Event.type == key_press_type) ||
           (Event.type == key_release_type) {
        int 루프;
        XDeviceKeyEvent * key = (XDeviceKeyEvent *) & Event;

        printf ( "key % s % d", (Event.type == key_release_type)? "release": "press", 키-> 키 코드);
        fprintf (stderr, "key % s % d", (Event.type == key_release_type)? "release": "press", 키-> 키 코드);

        for (loop = 0; loopaxes_count; 루프 ++) {
        printf ( "a [% d] = % d", 키-> first_axis + 루프, 키-> axis_data [loop]);
        }
        printf ( "\ n");
    }
    }
}

현재 내 생각은 리디렉션을 수행하면 프로그램이 키 누름 키 릴리스 이벤트를 모니터링하는 기능을 잃어 버릴 수 있다는 것입니다.



답변

stdout이 터미널이 아닌 경우 출력이 버퍼링됩니다.

그리고을 누르면 Ctrl-C버퍼가 아직 작성되지 않은 경우 손실됩니다.

를 사용하여 무엇이든 동일한 동작을 얻을 수 stdio있습니다. 예를 들어보십시오.

grep . > file

비어 있지 않은 몇 줄을 입력하고을 누르면 Ctrl-C파일이 비어있는 것을 볼 수 있습니다.

반면에 다음을 입력하십시오.

xinput test 10 > file

버퍼 가 가득 차도록 키보드에서 충분히 입력하십시오 (최소 4k에 해당하는 출력). 파일 크기가 한 번에 4k 단위로 커지는 것을 볼 수 있습니다.

을 사용하면 버퍼를 플러시 한 후 for 를 정상적으로 종료 grep할 수 있습니다 . 에 대해서는 그런 옵션이 없다고 생각합니다.Ctrl-Dgrepxinput

기본적 stderr으로 버퍼링되지 않아서 다른 동작을하는 이유를 설명합니다.fprintf(stderr)

에있는 경우 xinput.c, 당신은 추가 signal(SIGINT, exit), 그 말씀이다 xinput는 수신 정상적으로 때 종료 SIGINT당신이 볼 수없는 것, file무엇을 고려 : 안전이 보장되지는 신호 처리기에서 라이브러리 함수를 호출로 (이 충돌하지 않는 가정이 더 이상 비어 printf가 버퍼에 쓰는 동안 신호가 들어 오면 발생할 수 있습니다).

사용 가능한 경우 stdbuf명령을 사용 하여 stdio버퍼링 동작 을 변경할 수 있습니다 .

stdbuf -oL xinput test 10 > file

있습니다 이 사이트에 많은 질문 하지 않도록 다루 표준 입출력 당신이 더 많은 다른 솔루션을 찾을 수 있습니다 유형 버퍼링.


답변

명령은 /dev/tty정기적 인 리디렉션이 발생하지 않도록 직접 쓸 수 있습니다 .

$ cat demo
#!/bin/ksh
LC_ALL=C TZ=Z date > /dev/tty
$ ./demo >demo.out 2>demo.err
Fri Dec 28 10:31:57  2012
$ ls -l demo*
-rwxr-xr-x 1 jlliagre jlliagre 41 2012-12-28 11:31 demo
-rw-r--r-- 1 jlliagre jlliagre  0 2012-12-28 11:31 demo.err
-rw-r--r-- 1 jlliagre jlliagre  0 2012-12-28 11:31 demo.out


답변

xinput파일에 대한 출력은 거부하지만 터미널에 대한 출력은 거부하지 않는 것 같습니다 . 이를 위해서는 아마도 xinput시스템 호출을 사용하십시오

int isatty(int fd)

열 파일 설명자가 터미널을 참조하는지 여부를 확인합니다.

나는라는 프로그램으로 얼마 전에 같은 현상을 발견했다 dpic. 소스와 일부 디버깅을 살펴본 후 관련 줄을 제거 isatty하고 모든 것이 다시 예상대로 작동했습니다.

그러나 나는이 경험이 매우 혼란 스럽다는 것에 동의합니다.)


답변

당신의에서 test.c파일 당신은 사용 버퍼링 된 데이터를 플러시 할 수 (void)fflush(stdout);귀하의 직후 printf문.

    // in test.c
    printf("key %s %d ", (Event.type == key_release_type) ? "release" : "press  ", key->keycode);
    //fprintf(stderr,"key %s %d ", (Event.type == key_release_type) ? "release" : "press  ", key->keycode);
    //(void)fflush(NULL);
    (void)fflush(stdout);

명령 행에서 명령 xinput test 10으로 의사 터미널 (pty)에서 실행하여 라인 버퍼 출력을 사용할 수 있습니다 script.

script -q /dev/null xinput test 10 > file      # FreeBSD, Mac OS X
script -c "xinput test 10" /dev/null > file    # Linux


답변

예. 파스칼로 프로그래밍 할 때 DOS 시간 에도이 작업을 수행했습니다. 나는 원칙이 여전히 유지한다고 생각합니다.

  1. stdout 닫기
  2. 콘솔로 stdout을 다시여십시오
  3. 출력을 stdout에 씁니다.

이로 인해 파이프가 파손되었습니다.


답변