컷 출력을 리디렉션할 수 없습니다.

컷 출력을 리디렉션할 수 없습니다.

출력을 리디렉션하려고 하면 cut항상 비어 있는 것 같습니다. 리디렉션하지 않으면 출력이 예상대로 터미널에 나타납니다. OS X 10.10 및 Linux 4.1.6에서도 마찬가지입니다.

이것은 작동합니다:

root@karla:~# nc 10.0.2.56 30003
[...] lots of lines [...]

이것은 작동합니다:

root@karla:~# nc 10.0.2.56 30003 | cat
[...] lots of lines [...]

이것은 작동합니다:

root@karla:~# nc 10.0.2.56 30003 | cut -d, -f 15,16
[...] lots of lines [...]

이것은 아니다

root@karla:~# nc 10.0.2.56 30003 | cut -d, -f 15,16 | cat
[nothing]

이게 또하다

root@karla:~# cat messung1 | cut -d, -f15,16 | cat
[...] lots of lines [...]

cat이는 after 에만 국한되지 않습니다 cut. grep, tee표준 리디렉션을 사용해 >도 작동하지 않습니다.

무슨 문제가 있었나요?

답변1

출력이 없는 것이 아니라 덩어리로 출력됩니다.

많은 프로그램과 마찬가지로 cut해당 출력은 더 이상 터미널이 아닐 때 버퍼링됩니다. 즉, 버퍼가 가득 찼을 때만 데이터를 씁니다. 일반적으로 YMMV는 약 4 또는 8KiB입니다.

다음을 비교하여 이를 쉽게 확인할 수 있습니다.

(echo foo; sleep 1; echo bar) | cut -c2-

그리고:

(echo foo; sleep 1; echo bar) | cut -c2- | cat

첫 번째 경우에는 1초 후에 cut출력이 출력 oo\n되는 ar\n반면, 두 번째 경우에는 oo\nar\n1초 후에 출력이 차단됩니다. 즉, 입력의 끝을 확인하고 종료 시 출력을 플러시하는 경우입니다.

귀하의 경우 stdin은 nc연결이 닫힐 때만 입력의 끝을 볼 수 있으므로 쓸 데이터가 4KiB 축적된 후에만 출력을 시작합니다.

이 문제를 해결하기 위해 여러 가지 방법을 사용할 수 있습니다.

  • GNU 또는 FreeBSD 시스템에서는 stdbuf특정 명령의 버퍼링 동작을 조정할 수 있는 유틸리티를 사용할 수 있습니다(stdio 버퍼링 동작을 사전 구성하기 위해 LD_PRELOAD 해킹을 사용하기 때문에 모든 명령에 대해 작동하지는 않습니다).

    ... | stdbuf -oL cut -d, -f15,16 | cat
    

    cut표준 출력에서 ​​라인 기반 버퍼링을 수행하도록 지시합니다 .

  • GNU와 같은 일부 명령에는 grep버퍼링에 영향을 미치는 옵션이 있습니다. ( --line-bufferedGNU의 경우 grep).

  • pseudo-tty 래퍼를 사용하여 명령의 표준 출력을 터미널에 강제로 보낼 수 있습니다. 그러나 대부분의 이러한 솔루션에는 몇 가지 단점과 제한 사항이 있습니다. unbuffer expect예를 들어, 이러한 문제를 해결하기 위해 자주 언급되는 스크립트에는 버그가 많이 있습니다.

    잘 작동하는 것은 다음 socat과 같이 사용할 때입니다.

    ... | socat -u 'exec:"cut -d, -f15,16",pty,raw' -
    
  • 버퍼링되지 않은 출력을 지원하는 고급 텍스트 처리 도구로 텍스트 유틸리티를 대체할 수 있습니다.

    • awk예를 들어, GNU에는 fflush()출력을 플러시하는 기능이 있습니다. 따라서 귀하는 다음 cut -d, -f15,16과 같이 작성할 수 있습니다.

      awk -F, -vOFS=, '{print $15,$16;fflush()}'
      
    • awk해당 기능이 누락된 경우 해당 기능을 대신 fflush()사용할 수 있습니다 system(""). 이는 일반적으로 명령을 실행하는 명령입니다. 여기서는 빈 명령을 실행하지만 실제로는 awk명령을 실행하기 전에 명령의 표준 출력을 플러시하는 데 사용합니다.

    • 또는 다음을 사용할 수 있습니다 perl.

      perl -F, -lane 'BEGIN{$,=",";$|=1} print @F[14..15]'
      

관련 정보