segfault 이전의 출력이 정확히 필요한 것이기 때문에 segfault 프로그램을 디버깅하는 데 문제가 있습니다. 그러나 출력을 파일로 파이프하면 손실됩니다. 이 답변에 따르면:https://unix.stackexchange.com/a/17339/22615, 이는 프로그램의 출력 버퍼가 터미널에 연결되면 즉시 플러시되지만 파이프에 연결되면 특정 지점에서만 플러시되기 때문입니다. 여기에는 몇 가지 질문이 있습니다.
프로그램은 표준 출력이 무엇에 연결되어 있는지 어떻게 결정합니까?
"script" 명령은 프로그램이 터미널에 쓸 때와 동일한 동작을 어떻게 생성합니까?
스크립트 명령 없이 이 작업을 수행할 수 있습니까?
답변1
파일 설명자가 터미널 장치를 가리키는지 확인
프로그램은 다음 명령을 사용하여 파일 설명자가 tty 장치와 연결되어 있는지 여부를 확인할 수 있습니다.isatty()
ioctl()
표준 C 기능(보통 아래에서는 fd가 tty 장치를 가리키지 않을 때 오류를 반환하는 무해한 tty 관련 시스템 호출을 수행합니다 ).
[
/utility는 test
연산자를 통해 이를 수행할 수 있습니다 -t
.
if [ -t 1 ]; then
echo stdout is open to a terminal
fi
GNU/Linux 시스템에서 libc 함수 호출 추적:
$ ltrace [ -t 1 ] | cat
[...]
isatty(1) = 0
[...]
시스템 호출 추적:
$ strace [ -t 1 ] | cat
[...]
ioctl(1, TCGETS, 0x7fffd9fb3010) = -1 ENOTTY (Inappropriate ioctl for device)
[...]
파이프를 가리키는지 확인
fd가 파이프/FIFO와 연관되어 있는지 확인하려면 다음을 사용할 수 있습니다.fstat()
시스템 호출st_mode
, 이 fd에서 열린 파일의 유형과 권한이 필드에 포함된 구조를 반환합니다 . 이것S_ISFIFO()
표준 C 매크로st_mode
이 필드에서 fd가 파이프/FIFO인지 확인하는 데 사용할 수 있습니다 .
이를 수행할 수 있는 표준 유틸리티는 없지만 이를 수행할 수 있는 호환되지 않는 명령 구현이 fstat()
여러 개 있습니다 . 내장 함수는 패턴을 문자열 표현으로 반환하며 첫 번째 문자는 유형( 파이프의 경우)을 나타냅니다. GNU는 동일한 작업을 수행할 수 있지만 보고 도 해야 합니다.stat
zsh
stat
stat -sf "$fd" +mode
p
stat
stat -c %A - <&"$fd"
stat -c %F - <&"$fd"
유형홀로. BSD의 경우 stat
: stat -f %St <&"$fd"
또는 stat -f %HT <&"$fd"
.
검색 가능한지 확인
응용 프로그램은 일반적으로 stdout이 파이프인지 여부를 신경 쓰지 않습니다. 그들은 검색 가능한지 여부에 관심을 가질 수 있습니다(비록 일반적으로 버퍼링할지 여부를 결정하지는 않지만).
fd가 검색 가능한지 여부를 테스트하려면(파이프, 소켓, tty 장치는 검색할 수 없으며 일반 파일 및 대부분의 블록 장치는 일반적으로 검색 가능) 상대를 시도할 수 있습니다.lseek()
시스템 호출오프셋은 0입니다(그래서 무해합니다). dd
표준 유틸리티이자 인터페이스이지만 오프셋 0을 요청하면 구현에서 전혀 호출하지 않기 lseek()
때문에 이 테스트에서는 작동하지 않습니다 .lseek()
zsh
그리고 셸에는 ksh93
검색 연산자가 내장되어 있습니다.
$ strace -e lseek ksh -c ': 1>#((CUR))' | cat
lseek(1, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)
ksh: 1: not seekable
$ strace -e lseek zsh -c 'zmodload zsh/system; sysseek -w current -u 1 0 || syserror'
lseek(1, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)
Illegal seek
버퍼링 비활성화
이 script
명령은 의사 터미널 쌍을 사용하여 프로그램의 출력을 캡처하므로 프로그램의 stdout(stdin 및 stderr도 포함)은 의사 터미널 장치가 됩니다.
stdout이 터미널 장치인 경우 일반적으로 약간의 버퍼링이 있지만 라인 기반입니다. printf
/ puts
및 co는 개행 문자가 출력될 때까지 아무 것도 쓰지 않습니다. 다른 유형의 파일의 경우 버퍼링은 블록(킬로바이트) 단위로 수행됩니다.
버퍼링을 비활성화하는 몇 가지 옵션이 있으며, 이는 여기의 많은 Q&A에서 논의됩니다(검색버퍼링 해제또는표준 버퍼,컷 출력을 리디렉션할 수 없습니다.일부 방법은 의사 터미널(예: // socat
(script)/)을 사용하거나 실행 파일에 코드를 삽입하여 버퍼링을 비활성화하는 것(GNU 또는 FreeBSD에서 수행됨) 중 하나입니다.script
expect
unbuffer
expect
zsh
zpty
stdbuf