명령줄 프로그램이 출력이 리디렉션되는 것을 방지할 수 있습니까?

명령줄 프로그램이 출력이 리디렉션되는 것을 방지할 수 있습니까?

나는 이것을하는 데 익숙합니다. someprogram >output.file

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

  • someprogram 2>output.of.stderr.file (표준 오류의 경우)
  • 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
사용자@호스트 이름:~$

나는 이 출력이 평소와 같이 파일에 저장되기를 기대했습니다. 예를 들어 .를 사용했지만 xinput test 10 > output.file내 기대와는 달리 출력.파일 파일은 비어 있었습니다. 이는 또한 xinput test 10 &> output.filestdout이나 stderr에서 뭔가를 놓치지 않도록 하기 위한 것입니다.

정말 혼란스럽습니다. xinput출력이 리디렉션되는 것을 방지할 수 있는 방법이 있는지 여기에서 프로그램에 문의해 볼까요?

고쳐 쓰다

소스코드를 봤습니다. 이 코드에 의해 출력이 생성된 것 같습니다(아래 코드 조각 참조). 출력은 일반 printf에 의해 생성되는 것 같습니다.

//test.c 파일에서

정적 무효 print_events(*dpy 표시)
{
    XEvent 이벤트;

    그리고 (1){
    XNextEvent(dpy,&이벤트);

    // [...몇 가지 다른 이벤트 유형이 여기에 나열되어 있습니다...]

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

        printf("key %s %d ", (Event.type == key_release_type) ? "release" : "눌림", key->keycode);

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

stderr에서 출력 복사본을 얻을 수 있도록 소스 코드를 이것(아래의 다음 코드 조각 참조)으로 수정했습니다. 이 출력을 리디렉션할 수 있습니다.

//test.c 파일에서

정적 무효 print_events(*dpy 표시)
{
    XEvent 이벤트;

    그리고 (1){
    XNextEvent(dpy,&이벤트);

    // [...몇 가지 다른 이벤트 유형이 여기에 나열되어 있습니다...]

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

        printf("key %s %d ", (Event.type == key_release_type) ? "release" : "눌림", key->keycode);
        fprintf(stderr,"key %s %d ", (Event.type == key_release_type) ? "release" : "press ", key->keycode);

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

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

답변1

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)지시하면 더 이상 null이 아니라는 것을 알 수 있습니다 (신호 처리기에서 라이브러리 함수를 호출하는 것이 안전하다고 보장되지 않으므로 충돌하지 않는다고 가정). printf가 버퍼에 쓰는지 고려하십시오. 이는 신호가 영역에 들어갈 때 발생할 수 있습니다.xinputSIGINTfile

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

stdbuf -oL xinput test 10 > file

가지다이 사이트에 질문이 많아요이 재정의는 비활성화됩니다.표준 입력 및 출력버퍼링을 입력하면 더 많은 대체 솔루션을 찾을 수 있습니다.

답변2

/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

답변3

xinput파일 출력은 거부하지만 터미널 출력은 거부하는 것 같습니다 . 이를 달성하기 위해 xinput시스템 호출을 사용할 수 있습니다.

int isatty(int fd)

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

얼마 전 나는 이라는 프로그램에서 같은 현상을 우연히 발견했습니다 dpic. 소스 코드를 살펴보고 디버깅을 한 후 관련 줄을 제거하고 isatty모든 것이 다시 예상대로 작동했습니다.

하지만 나는 당신의 말에 동의합니다. 이 경험은 매우 충격적입니다. ;)

답변4

예. 나는 파스칼로 프로그래밍하던 DOS 시절에도 이런 일을 했습니다. 나는 다음과 같은 원칙이 여전히 유효하다고 생각합니다.

  1. 표준 출력 닫기
  2. 콘솔로 표준 출력 다시 열기
  3. 표준 출력에 출력 쓰기

이는 실제로 모든 파이프라인을 중단시킵니다.

관련 정보