cut -c의 표준 출력 라인 버퍼링이 cut -b의 버퍼링과 다른 이유는 무엇입니까?

cut -c의 표준 출력 라인 버퍼링이 cut -b의 버퍼링과 다른 이유는 무엇입니까?

RHEL 7 시스템에는 매우 긴 로그 파일이 있어서 컷 버퍼링에 대해 문의했습니다.이것질문. 문제는 여전히 존재하지만 일부 실험에서는 다른 문제가 나타납니다.

나는 문자 단위로 분할하는 대신 바이트 단위로 분할을 사용하기로 결정했고 출력 버퍼링이 한 컴퓨터에서는 다르지만 다른 컴퓨터에서는 그렇지 않다는 것을 발견했습니다.

한 머신에는 두 개의 루프가 있습니다.

for ((ii=0;ii<5;ii++)); do  date; usleep 500000 ; done |  cut -b 1-99
for ((ii=0;ii<5;ii++)); do  date; usleep 500000 ; done |  cut -c 1-99

(관찰 -cvs -bfor cut) 둘 다 루프가 진행됨에 따라 날짜를 5번 표시합니다.

다른 머신에서는 이 루프가 바이트 단위로 자릅니다.

for ((ii=0;ii<5;ii++)); do  date; usleep 500000 ; done |  cut -b 1-99

루프가 진행되는 동안 시간을 ​​표시합니다.

for ((ii=0;ii<5;ii++)); do  date; usleep 500000 ; done |  cut -c 1-99

루프가 완료될 때까지 출력을 유지합니다. 영원히 실행되도록 설정하면 8192바이트의 출력마다 일련의 횟수가 표시됩니다. 예상대로 초당 두 번이지만 출력이 버퍼링됩니다.

두 가지 질문,

  1. 한 시스템이 다른 시스템과 다른 이유는 무엇입니까?
  2. 두 가지 cut 사용에 대해 출력 버퍼가 다른 이유는 무엇입니까?

답변1

이것은 아니다표준 출력사실 이번에는 버퍼링이 아닙니다. (표준 출력 버퍼링의 기본 설정은 라인 버퍼 출력만 터미널로 보내는 것입니다.)

우선, 이는 업스트림 coreutils 기능이 아니며 Debian과 같은 시스템에서는 이 문제가 표시되지 않습니다. 매뉴얼 페이지와 출력 내용에 관계없이 --help실제 업스트림 코드는 동일한 -c것으로 간주됩니다. 예를 들면 다음과 같습니다.-bhttps://github.com/coreutils/coreutils/blob/v9.1/src/cut.c#L483

coreutils-i18n그러나 로케일 기반 멀티바이트 문자를 지원하는 국제화 패치가 있으며 Red Hat은 해당 패치를 제공하는 것으로 보입니다.

패치는 여기에 사용할 별도의 입력 버퍼링 매크로도 제공합니다 cut -c.

+/* Refill the buffer BUF to get a multibyte character. */
+#define REFILL_BUFFER(BUF, BUFPOS, BUFLEN, STREAM)                        \
+  do                                                                        \
+    {                                                                        \
+      if (BUFLEN < MB_LEN_MAX && !feof (STREAM) && !ferror (STREAM))        \
+        {                                                                \
+          memmove (BUF, BUFPOS, BUFLEN);                                \
+          BUFLEN += fread (BUF + BUFLEN, sizeof(char), BUFSIZ, STREAM); \
+          BUFPOS = BUF;                                                        \
+        }                                                                \
+    }         
+  while (0)
      

이것은 루프는 아니지만 fread()EOF까지 또는 버퍼가 가득 찰 때까지 차단됩니다. (not) 에서 프로그램을 실행하면 ltrace내가 시도한 CentOS 시스템에서 차단되는 것으로 표시됩니다 strace.fread_unlocked()

이에 대해 당신이 할 수 있는 일은 아무것도 없습니다. 구현은 stdio에 BUFLEN바이트를 원한다고 알려주고 그게 전부입니다. 아니요, 입력 버퍼링을 비활성화하면 응용 프로그램에 필요한 것보다 미리 stdio 읽기에만 영향을 미치기 때문에 도움이 되지 않습니다.

적어도 과거에는 i18n 패치에도 다른 문제가 있는 것 같습니다.https://lwn.net/Articles/535735/그리고https://bugzilla.redhat.com/show_bug.cgi?id=499220


ASCII 문자만 있는 경우 다른 Linux 시스템에서 cut -b와 동일한 방식 으로 전환할 수 있습니다. cut -c또는 perl -C -ne 'print substr($_, 0,99)'.

관련 정보