대화형 명령에서 "tee"로 끝나는 파이프로 전달된 출력을 어떻게 버퍼링 해제할 수 있나요?

대화형 명령에서 "tee"로 끝나는 파이프로 전달된 출력을 어떻게 버퍼링 해제할 수 있나요?

     대화형 명령 문제를 해결하고 싶은데 다음을 수행하고 싶습니다.

  • 버퍼링이나 라인 버퍼링 없이 원래 색상으로 화면에 인쇄된 출력물을 봅니다.막힌-buffered,) 명령이 생성하기 때문입니다.
  • 이와 같은 것을 사용하면 tee이 명령의 출력을 파일로 동시에 리디렉션하여 보존할 수 있습니다. 즉, 왜곡되지 않습니다(예: 다음을 전달하여).ANSI 이스케이프 시퀀스올바르게 처리하는 대신 원시 데이터로) - 생성된 로그 파일의 색상입니다. (이 기본 설정의 일부가 가능하지 않을 수 있음을 인식하여 다음 기본 설정으로 대체합니다.)
  • 또한 다음을 사용하여 tee이 명령의 출력을 파일로 리디렉션합니다.
  • 런타임 시 해당 명령의 색상으로 출력 표시
  • 생성된 로그를 오염시키지 않습니다.ANSI 이스케이프 시퀀스 - 즉, 터미널에 표시한 후 출력에서 ​​제거하지만앞으로로그 파일에 저장합니다.

일반적으로 tee -a여기에 로그인하려고 하는 것과 동일한 종류의 명령 출력을 사용하는 것은 나에게 매력적으로 작동하지만일부파이프라인에서 내가 만난 이상한 코너 케이스는 tee이러한 정상적이고 합리적인 동작을 깨뜨리는 것처럼 보였습니다. 내가 하나 만들었어소량이전에 비슷한 문제를 겪은 사람이 있는지 알아보고 해결책을 제안했지만 제가 찾아낸 관련 자료는 모두 다음과 같습니다.

그러나 이러한 리소스 중 어느 것도상당히충분한 힌트가 주어지면, 나는 그것을 사용하여 내가 원하는 것에 맞는 것을 거의 내가 원하는 만큼 빨리 엮을 수 있을 것이라고 생각했습니다.좋다 -마침내 도움이 필요한 로그를 생성할 수 있는 사람에게 전달할 수 있습니다.찾다물론 그들도 몇 가지 물건을 가지고 있습니다.
     나는 가지고있다시험을 마친내가 읽은 내용에는 unbuffer- 및 -를 기반으로 한 몇 가지 다양한 조언이 제공되었으며 이 질문을 쓰기 시작하기 전에 몇 가지 제공을 고려하고 있었지만 아직 마지막 조언을 수행하지 못했습니다. 저는 OS X v10.11.6 "El Capitan"을 사용하고 있습니다. 문제를 해결하려는 명령은 다음과 같습니다.scriptstdbuf/usr/bin/bashHOMEBREW_BUILD_FROM_SOURCE=1 brew upgrade -vd --build-from-source mailutilsbrew홈브루 패키지 관리자소스에서 빌드하고 업그레이드하려고 하는 Mailutils 버전은 v3.3입니다(현재 v3.2를 사용하고 있습니다).깊은완전히 바꾸는 건 의문다른그걸 주문해반품파이프라인의 일부로 사용되면 청크 버퍼링된 출력이 생성됩니다(내가 이해하는 경우).바르게, 할 것이다어느쉘 명령을 실행하면 파이프 자체를 설정하면 블록 버퍼링이 발생할 수 있다고 언급되어 있지만 문제는 해결되지 않습니다. 여기에서 캡처하려는 로그로 원하는 결과를 얻으려면 어떤 도구를 사용할 수 있나요?

답변1

프로세스 대체1 변화시키자script이것이 타이프스크립트에 나와 있는 내용입니다.

이스케이프 시퀀스가 ​​제거된 로그를 작성하는 대신 임의의 명령을 사용하여 이를 제거하는 스크립트를 실행할 수 있습니다. 비교적 새로운 버전의 macOS나 FreeBSD 이외의 시스템에서는 구현마다 지원하는 옵션이 다르기 때문에 명령이 약간 다릅니다. 자세한 내용은 아래를 참조하세요.script -q >(./dewtell >>outfile) brew args...script -aq outfile brew args..../dewtellscript

지금까지의 이야기(대체 솔루션 포함)

귀하의 솔루션

명령 은 스크립트 및 brew와 같은 여러 가지 다른 출력 생성 프로그램을 하위 프로세스로 실행하며 출력을 로 파이핑하면 출력 (적어도 일부 하위 프로세스의)이 버퍼링되어 터미널에 표시되지 않습니다. 실시간../configuremakebrewteebrew args... 2>&1 | tee -a outfile

당신은 알아냈어요script다음을 실행하여 script -aq문제를 해결했습니다 .표준 출력터미널 2-k , 자신의 입력을 녹음하려면 다음을 통해 수행할 수도 있습니다.터미널에 울리지 않고 입력하더라도. 당신은 더 많은 것을 발견합니다두테르테의 확장판~의Gilles의 Perl 스크립트도착하다파일에서 이스케이프 시퀀스 제거생성된 TypeScript를 효율적으로 정리하여 필요한 것으로 변환합니다.

Gilles의 원본 스크립트와 dewtell의 확장 버전 간의 차이점은 둘 다 색상 변경을 지정하는 것을 포함하되 이에 국한되지 않는 이스케이프 시퀀스를 제거하는 반면 dewtell의 스크립트는 캐리지 리턴( 및 의 출력에서 $'\r'​​로 표시됨 )도 제거한다는 것입니다. 백스페이스 문자( 및 의 출력에 표시됨 ) 및 삭제된 것으로 보이는 문자(있는 경우)로 표시됩니다.^Mvimcat -v$'\b'^Hvimcat -v

특정 Perl 구현 관련 문제

스크립트에 "비교적 새로운" Perl 인터프리터가 필요하다고 보고했습니다. 하지만 새로운 기능은 필요하지 않습니다.use또는 그렇지 않으면 이에 의존하는 것 같고 macOS 10.11.6 El Capitan을 실행하는 내 친구가 시스템 제공 Perl 5.8.12에서 작동한다는 것을 확인했기 때문에 최신 버전이 필요한 이유(또는 경우)를 모르겠습니다. 펄 하나.기대했다최대사람들은 자신이 가지고 있는 Perl을 사용할 수 있습니다.

하지만 대본은실패했다Mac mOS 의 경우 ​​​​​그러면 이 문제는 . 이로 인해 색상이 지정된 이스케이프 시퀀스 조각이 출력에 남아 있게 됩니다. 이러한 시퀀스는 일치할 수 없고 나중에 대체 시퀀스가 ​​대신 일치되기 때문입니다 . 그리고[@-~]LC_COLLATE=CLC_ALL=Cgrepsedpythonruby(?:\e\[|\x9b) [ -?]* [@-~]\e.perlbrew, 저는 이 시스템에 Perl 5.27.5, 5.8.9, 심지어 5.6.2도 설치했습니다. 아무도 이 문제를 겪지 않았습니다.

스크립트를 실행하기 위해 다른 곳에 설치된 Perl 인터프리터가 정말로 필요하거나 사용하려는 경우 /usr/bin/perl다음을 변경할 수 있습니다.해시 스틱맨 위의 줄은 올바른 경로를 가리킵니다. 또는 /usr/bin/env perl원하는 perl실행 파일이 경로에 먼저 나타나는지 여부, 즉 perl입력하고 누르면 실행될지 여부 로 변경될 수 있습니다 Enter. 또는 스크립트의 파일 이름을 첫 번째 인수로 사용할 수 있습니다. 예를 들어 . /usr/local/bin/perl dewtell대신 인터프리터를 명시적으로 호출합니다 ../dewtell

원본 타이프스크립트를 보존하거나 교체하는 방법

TypeScript에서 이스케이프 시퀀스를 제거해야 하는 일부 사용자는 처리되지 않은 이전 TypeScript를 유지하기를 원합니다. 그러한 사용자가 이름이 지정된 TypeScript를 처리 dirty.log하고 여기에 출력을 쓰려 는 경우 필요한 경우 실행된 다른 명령을 대체하여 clean.log실행합니다../dewtell dirty.log > clean.log./dewtell두테르테의 대본(또는 사용하려는 다른 스크립트).

TypeScript를 "제자리"로 수정하려면 -i에 전달하여 perl실행 하면 됩니다.perl -i.orig dewtell typescripttypescript는 에서 생성된 타이프 스크립트 script, .orig는 백업 파일에 사용되는 접미사, dewtell은 Perl 스크립트입니다. 또는 백업 접미사가 제공되지 않으므로 원본 파일을 삭제하는 대신 실행할 수도 있습니다. 이러한 방법은 모든 Perl 스크립트에 적용되지는 않지만 입력을 읽고 이 스크립트에 적용됩니다.perl -i dewtell typescript<><>펄 측에서는-i.

sponge원래 타이프스크립트에 변경 사항을 다시 기록 하곤 했습니다 . 이 방법 역시 훌륭하고 신뢰할 수 있는 방법입니다.더 많은 유틸리티설치되어 있습니다.

이스케이프 시퀀스가 ​​기록되지 않도록 방지

남은 질문은 처음에 이스케이프 시퀀스가 ​​제거된 로그를 작성하는 방법입니다. ~처럼당신은 말한다:

[T] 이 모든 것을 단일 파이프로 연결하는 방법도 있을 수 있지만 글을 쓰는 시점에는 다른 의견이나 답변에서 방법을 알 수 없었습니다.

파이프 대신 프로세스 대체를 사용하십시오.

문제는 script대부분의 (모든?) 시스템에서 이러한 변환을 지원하는 옵션이 없다는 것입니다. script기록된 파일의 이름은 사용자가 지정한 이름이거나 기본값 typescript(표준 출력 아님) 이므로 파이핑은 scriptTypeScript에 기록되는 내용에 영향을 미치지 않습니다.

script파이프 연산자( ) 오른쪽에 명령을 배치하여 파이프합니다.|도착하다이것도 좋은 생각이 아닙니다. 귀하의 경우 이는 특히 brew표준 출력이 파이프일 때 출력 또는 해당 하위 프로세스가 버퍼링되어 표시해야 할 때 표시되지 않기 때문입니다.

이 문제가 해결되더라도 합리적으로 사용할 수 있는 방법은 없습니다.관로1 이 작업을 함께 script완료합니다 .

그러나 이는 프로세스 교체를 통해 수행될 수 있습니다.3 인치프로세스 교체1 (또한여기에 설명되어 있습니다), 당신은 또는. 쉘은<(command...)>(command...)명명된 파이프표준 출력 또는 입력으로 각각 사용하십시오.서브쉘~에command...달리기. 텍스트 또는는 명명된 파이프의 파일 이름으로 대체됩니다.<(command...)>(command...)치환--따라서 프로그램에 매개변수로 전달하거나 리디렉션 대상으로 사용할 수 있습니다.

  • 달리기를 위해<(command...)command...좋다그 출력원하는 파일의 내용입니다다음에서 읽기. 4
  • 달리기를 위해>(command...)command...좋다입력원하는 파일의 내용입니다에게 편지를 쓰다. 4

모든 시스템이 명명된 파이프를 지원하는 것은 아니지만 대부분은 지원합니다. 모든 쉘이 프로세스 대체를 지원하는 것은 아니지만 Bash는 이를 지원하며, Bash 버전은 이를 지원할 수 있는 시스템에서 실행되고 POSIX 모드가 쉘에서 꺼져 있는 한 이에 대한 지원을 무시하지 않습니다. 세게 때려대개특히 원격 최신 운영 체제를 사용하는 경우 프로세스 교체에 액세스할 수 있습니다. Mac OS X 10.4.11 Tiger(PPC) 시스템에서도 "$BASH_VERSION"프로세스 2.05b.0(1)-release교체가 제대로 작동합니다 .

script최신 macOS 시스템에서 s 구문을 사용할 때 이를 수행하는 방법은 다음과 같습니다.

이는 macOS 10.11 El Capitan 시스템에서 작동하며 다음을 통해 작동합니다.해당 맨페이지, 모든 macOS 시스템이것은 적어도 macOS 10.9 Mavericks로 돌아갑니다.아마도 이전:

script -q >(./dewtell >>clean.log) brew args...

사용자 입력을 포함하여 터미널에 기록된 모든 내용을 기록합니다.그것이 당신에게 다시 에코되면, 즉 터미널에 나타나는 경우 일반적으로 그렇습니다. 자신의 입력을 기록하고 싶다면나타나지 않더라도, 이는 일반적으로 비밀번호를 입력할 때 발생하므로너의 답-k, 옵션 추가 :

script -kq >(./dewtell >>clean.log) brew args...

두 경우 모두 ./dewtell실행하는 명령으로 바꾸십시오.두테르테의 대본또는 출력을 필터링하는 데 사용하려는 다른 프로그램이나 스크립트,clean.log여기에는 typescript에 기록될 파일 이름(이스케이프 시퀀스 생략)이 포함되어 있고 5에는 실행 중인 명령과 해당 인수가 포함되어 있습니다.brew args...

로그에 덮어쓰기 또는 추가

재정의하고 싶다면clean.log파일에 추가한 다음 .을 사용하는 대신 프로세스 대체를 통해 실행되는 명령에 의해 실제 파일이 기록되므로 .>clean.log>>clean.log>>>>( )

>>(not 을 사용하려고 하지 마십시오 >(. 구문 오류이며 프로세스 대체가 리디렉션을 의미하지 않기 때문에 의미가 >없습니다 >(.

이 경우 로그 파일을 덮어쓰는 것을 방지하려면 -a로 전달하지 마십시오 . 이 파일은 그냥 열리게 됩니다.script명명된 파이프추가 모드 - 일반 쓰기를 위해 여는 것과 동일한 효과가 있습니다. 그런 다음 덮어쓰거나 추가합니다.clean.log, 여전히 서브 쉘에서 또는 가 사용되는지 여부에 따라 다릅니다.>clean.log>>clean.log

마찬가지로 내부적으로(또는 어디에서나) >&or 를 사용하거나 추가하지 마세요 &>. 오류나 경고가 생성되면 작성하기보다는 확인하고 싶을 것이기 때문입니다.2>&1>( )./dewtellclean.log. 이 script명령은 TypeScript에 표준 오류의 텍스트를 자동으로 포함합니다. 이를 위해 특별한 작업을 수행할 필요가 없습니다.

다른 운영 체제에서

~처럼너의 답설명하다:

[S] script이 명령의 일부 버전은 구문이 다릅니다. 제공된 버전은 OS X/macOS용이므로 필요에 따라 조정하세요.

GNU/리눅스

대부분의 GNU/Linux 시스템은 script다음에서 제공하는 구현을 사용합니다.유틸리티Linux. 쉘을 시작하는 대신 특정 명령을 실행하려면 해당 -c옵션을 사용하고 전체 명령을 다음과 같이 전달해야 합니다.단일 명령줄 매개변수to 로 script묶으면 이를 따옴표로 묶어서 수행할 수 있습니다. 이는 와 같은 최신 macOS 시스템의 버전과 다릅니다 script. 이 버전에서는 출력 파일 이름 뒤에 배치된 여러 인수로 명령을 자연스럽게 전달할 수 있습니다( 와 같은 옵션 없이 -c).

그래서Debian, Ubuntu, Fedora, CentOS 및 대부분의 기타 GNU/Linux 시스템, 다음 명령을 사용할 수 있습니다( brew명령 6 이 있는 경우 또는 이를 실행하고 변환된 출력을 기록하려는 명령으로 바꾸십시오).

script >(./dewtell >>clean.log) -qc 'brew args...'

script시스템에서 와 마찬가지로 GNU/Linux에서 로깅 시작 및 종료 방법에 대한 추가 메시지를 포함 -q하려면 제거하십시오. script이 옵션을 사용하더라도 -q이 버전에는 script실행이 시작된 시점을 나타내는 줄이 상단에 포함되어 있지만 표시되지는 않습니다.그 줄은 언제 쓰여졌는지에 대한 정보를 쓰거나 표시하지 않습니다.중지됨달리기.

선택의 여지가 없다 -k. 터미널에 나타나는 텍스트만 기록됩니다. 7

FreeBSD

macOS의 명령은 scriptFreeBSD에서 시작됩니다. 모든 버전은 -a덮어쓰기 대신 추가를 지원합니다(그러나 위에서 언급한 것처럼 프로세스 대체를 사용하여 명명된 파이프 위에 쓸 때 추가하는 데 도움이 되지 않습니다). -a다음을 포함하는 유일한 옵션입니다.프리BSD 2.2.5. 옵션 -q은 다음과 같습니다FreeBSD 2.2.6에 추가됨. 옵션 -k은 다음과 같습니다FreeBSD 2.2.7에 추가됨.

위로FreeBSD 2.2.5를 통해, 이는 script특정 명령이 주어지는 것을 허용하지 않지만, 변수가 설정되지 않은 경우 대체로 SHELL환경 변수에 의해 주어진 사용자 셸을 항상 실행합니다./bin/shFreeBSD 2.2.6부터 시작script, 셸 대신 실행될 명령줄에 특정 명령을 제공할 수 있습니다 .

script따라서 최신 버전의 FreeBSD(현재 일반적인 버전 포함)는 명령을 호출하는 방식에서 최신 macOS 시스템(예: 사용자 시스템)과 유사합니다. 마찬가지로, 이전 버전의 FreeBSD는 이전 버전의 macOS와 유사합니다(아래 참조).

perl최신 버전에서는 FreeBSD 기본 시스템의 일부가 아니며, 그런 bash적도 없습니다. 둘 다 pkg install perl5 bash bash-completion패키지(예: with) 또는 포트를 사용하여 쉽게 설치할 수 있습니다 . FreeBSD에서 제공하는 시스템은 /bin/sh프로세스 대체를 지원하지 않습니다.

이전 버전의 macOS 및 다양성이 떨어지는 기타 시스템script

저는 Mac OS X 10.4 Tiger에서 테스트했습니다 script.오직옵션 -a. -q또는 을 허용하지 않습니다 -k. GNU/Linux 시스템의 util-linux 버전과 마찬가지로 typescript 7 의 터미널에 표시된 키 입력만 포함됩니다 .

적어도 각 macOS 버전에 대한 신뢰할 수 있는 문서 소스를 찾을 수 있을 때까지는 script(내가 아는 한10.9 매버릭스 맨페이지온라인에서 쉽게 구할 수 있음)macOS 사용자에게 다음을 실행하는 것이 좋습니다.man scriptscript해당 명령이 허용하는 구문, 기본적으로 작동하는 방식, 지원하는 옵션을 확인하세요 . 나와 같은 이전 버전의 macOS에서는 다음 명령을 사용할 수 있습니다.

script >(./dewtell >>clean.log)
brew args...
exit

이는 다음에도 적용됩니다.script 많은 옵션을 지원하지 않는 기타 운영 체제, 또는 다른 옵션을 지원하지만 해당 옵션을 사용하고 싶지 않은 운영 체제에서. 이 방법 script은 셸을 시작하고 셸에 기록해야 하는 모든 명령을 실행한 다음 셸을 종료하는 전통적인 방법입니다.

명령을 가장하는 추악한 해킹은 쉘입니다.

쉘의 새 인스턴스가 아닌 단일 명령을 실행하기 위해 실제로 이를 사용해야 하는 경우 script때때로 추악한 해킹을 사용할 수 있습니다. 실행하려는 명령이 실제로 쉘이라고 생각하도록 속일 수 있습니다. 하지만 이 작업을 수행하기 전에 두 번 생각해야 합니다.SHELL=your-command script outfileyour-command실제로는 SHELL환경 변수를 참조하여 사용 중인 실제 쉘을 확인하고, 유감스럽게도 불행한 동작이 발생합니다.

게다가 여러 단어로 구성된 명령(예: 하나 이상의 인수를 전달하는 명령)의 경우 이는 쉽지 않습니다. 이전에 같은 줄에 썼다면 값이 환경에 성공적으로 전달되지만 첫 번째 단어뿐만 아니라 전체 문자열이 명령 이름으로 사용되며 명령 대신 인수가 전달되지 않습니다. 다른 모든 단어는 통과되었습니다.SHELL='brew args...'scriptbrew args...scriptSHELL

다음에서 실행되는 쉘 스크립트( run-brew또는 원하는 대로 호출) 를 작성하여 이 문제를 해결할 수 있습니다.brewargs...을 선택한 다음 이를 환경 변수의 값으로 전달합니다 SHELL. run-brew셸 스크립트를 생성 한 후 명령을 통해 실행하면 script다음과 같습니다.

SHELL=run-brew script >(./dewtell >>clean.log)

위에 제시된 이유로 인해 SHELL수행 중인 작업이 중요하지 않거나 를 사용하지 않을 것이라고 확신하지 않는 한 명령 이름을 할당하는 방법을 사용하지 않는 것이 좋습니다 SHELL. Homebrew는 상당히 복잡한 작업을 많이 수행하므로 실제로 run-brew그러한 스크립트를 실행하지 않는 것이 좋습니다. (길고 복잡한 brew명령을 스크립트에 넣는 데에는 아무런 문제가 없습니다 run-brew. 그냥 SHELL=run-brewmake를 사용하여 script실행하세요.)

그러나 위에 표시된 기술을 테스트하기 위해 간단한 프로그램과 함께 사용할 때 이 접근 방식이 다소 유용하다는 것을 알았습니다.brew args...

기술 테스트 및 시연

긴 명령보다 더 복잡한 명령에 대해 이러한 방법 중 일부를 시도해 보는 것이 유용할 수 있습니다 brew. 나는 내가 그랬다는 것을 안다.

데모 프로그램/테스트 입력 생성기 및 사용된 테스트 방법

나는 표준 오류에 쓰고 표준 출력에서 ​​사용자의 이름을 묻는 메시지를 표시하고 표준 입력에서 읽은 다음 표준 출력에 인사말을 쓰고 사용자를 색상 이름으로 표시하는 간단한 대화형 Perl 스크립트를 만들었습니다.

#!/usr/bin/perl

use strict;
use warnings;
use Term::ANSIColor;

print STDERR $0, ": warning: this program is boring\n";
print "What's your name?  ";
chomp(my $name = <STDIN>);
printf "Hello, %s!\n", colored($name, 'cyan');

불러서 colorhi넣는다두테르테의 대본, 나는 그것을 이라고 부른다 dewtell.

내 테스트에서는 #!/usr/bin/perl두 스크립트를 모두 교체했습니다. 8 시스템 제공 Perl 5.22.1 및 제공 버전 5.6.2 및 5.8.9를 사용하고 FreeBSD 11.1-RELEASE-p3 및 제공 Perl 5.24.3 및 버전 5.6.2, 5.8.9 및 5.27.5를 사용하여 Ubuntu 16.04 LTS에서 테스트했습니다. ; 맥 OS#!/usr/bin/env perlperlbrewpkgperlbrewperlbrew

각 Perl 버전에 대해 아래에 설명된 테스트를 반복했습니다. 먼저 시스템에서 제공하는 9 버전을 테스트한 다음 일시적으로 사용하여 제공된 perlbrew use각 바이너리가 먼저 나타나도록 했습니다 (예를 들어 Perl 5.6.2를 테스트하기 위해 실행한 후 다음이 표시됩니다). 테스트 중인 시스템에 대한 명령).perlbrewperl$PATHperlbrew use 5.6.2

친구가 원래 hashbang 라인을 사용하여 macOS 10.11.6 El Capitan에서 테스트한 결과 시스템에서 제공한 perl 5.18.2를 사용하고 다른 인터프리터는 테스트하지 않았습니다. 이 테스트에서는 FreeBSD에서 테스트할 때 실행한 것과 동일한 명령을 사용합니다.

Mac OS X 10.4.11 Tiger에서 시스템 제공 Perl을 제외하고 이러한 모든 테스트는 성공적이었습니다., 아래 예제와 같이 이전에 자세히 설명한 것처럼 정규식의 문자 클래스와 관련된 이상한 오류로 인해 실패했습니다.

우분투에서

스크립트가 포함된 디렉터리에서 Ubuntu 시스템에서 다음 명령을 실행하여 이스케이프 시퀀스와 입력할 수 있는 백스페이스 문자가 포함된 TypeScript를 생성합니다.

printf 'Whatever header you want...\n\n' >dirty.log
script dirty.log -aqc ./colorhi

나는 그것을 입력 Eliah한 다음 더 나은 생각인 것처럼 행동하고 백스페이스 키로 삭제하고 를 입력했습니다 Bob from accounting. 그런 다음 그것을 눌렀 Enter더니 색깔이 반겨주었습니다. 그런 다음 다음 명령을 실행합니다.각기이스케이프 시퀀스 없이, 실제 이름을 표시하지 않고 타이프스크립트를 생성하고, 정확히 동일한 방식으로 상호작용합니다(타이핑 및 지우기 포함 Eliah).

printf 'Whatever header you want...\n\n' >clean.log
script >(./dewtell >>clean.log) -qc ./colorhi

vim제어 문자를 기호적으로 표시 cat -v하고 밝은 텍스트나 색상 텍스트의 장점을 제공합니다. 표시된 버퍼는 다음과 같지만 view dirty.log제어 문자는 이탤릭체로 표시되어 눈에 띕니다.

Whatever header you want...

Script started on Thu 09 Nov 2017 07:17:19 AM EST
./colorhi: warning: this program is boring^M
What's your name?  Eliah^H ^H^H ^H^H ^H^H ^H^H ^HBob from accounting^M
Hello, ^[[36mBob from accounting^[[0m!^M

버퍼의 모습은 다음과 같습니다 view clean.log.

Whatever header you want...

Script started on Thu 09 Nov 2017 07:18:31 AM EST
./colorhi: warning: this program is boring
What's your name?  Bob from accounting
Hello, Bob from accounting!

결과는 타임스탬프를 제외하고 테스트된 모든 인터프리터에 대해 동일합니다.

FreeBSD(및 macOS 10.11.6 El Capitan)

다음 명령을 사용하여 빌드했다는 점을 제외하면 Ubuntu에서와 동일한 방식으로 FreeBSD에서 테스트했습니다 dirty.log.

printf 'Whatever header you want...\n\n' >dirty.log
script -aq dirty.log ./colorhi

다음 명령을 사용하여 다음을 생성합니다 clean.log.

printf 'Whatever header you want...\n\n' >clean.log
script -q >(./dewtell >>clean.log) ./colorhi

이것은 내 친구가 macOS 10.11에서 테스트할 때 실행한 것과 동일한 명령입니다.Eliah, 내보낸 입력이 내 / 입력 과 약간 다르지만 Bob from accounting여전히 이름을 입력하고 백스페이스로 삭제한 다음 다른 이름으로 바꿉니다. 따라서 백스페이스 키의 이름과 수를 제외하면 출력은 유사합니다.

네 가지 Perl 구현은 모두 FreeBSD에서 테스트되었으며 하나(시스템 제공) 구현은 macOS 10.11에서 테스트되었으며 둘 다 예상된 출력을 dirty.log보여줍니다 . clean.logFreeBSD 결과를 Ubuntu 결과와 비교해 보면 타임스탬프가 없다는 점이 다릅니다. 이는 제거를 나타내는 모든 백스페이스 및 백스페이스 문자와 마찬가지로 모든 -q이스케이프 시퀀스 및 캐리지 리턴이 에서 성공적으로 제거되었기 때문입니다.clean.log

Mac OS X 10.4.11 타이거

다음 명령을 사용하여 빌드했다는 점을 제외하면 Ubuntu 및 FreeBSD와 동일한 방식으로 기존 Tiger 시스템에서 테스트했습니다 dirty.log.

printf 'Whatever header you want...\n\n' >dirty.log
SHELL=colorhi script -a dirty.log

다음 명령을 사용하여 다음을 생성합니다 clean.log.

printf 'Whatever header you want...\n\n' >clean.log
SHELL=colorhi script >(./dewtell >>clean.log)

시스템 script명령이 지원되지 않으므로 -q결과는 다음과 같습니다.(ㅏ)Script started제목 뒤에 줄 추가(둘)개행 문자 다음에는 Script done각 타이프스크립트의 끝에 한 줄이 추가됩니다. 두 줄 모두 타임스탬프를 포함합니다. 그렇지 않으면 결과는 Ubuntu 및 FreeBSD와 동일합니다.청록색 텍스트 간 전환을 위한 시스템 제공 이스케이프 시퀀스가 ​​완전히 제거되지 않았습니다.perl. 예상대로 관련 줄은 항상 dirty.log다음과 같이 나타납니다 vim.

Hello, ^[[36mBob from accounting^[[0m!^M

시스템 제공 Perl 5.8.6에서 이는 clean.log디스플레이 6m및 의 해당 행이며 0m제거되어야 하며 다음과 같습니다.

Hello, 6mBob from accounting0m!

설치된 모든 perlbrewPerl에 대해 모든 이스케이프 시퀀스가 ​​정확하고 올바르게 제거되며 Ubuntu 및 FreeBSD에서 실행하는 모든 Perl 인터프리터에서와 마찬가지로 행은 다음 clean.log과 같습니다.

Hello, Bob from accounting!

노트

1 그 매뉴얼배쉬 2와 함께 작동합니다. 많은 Bash 사용자는 주요 버전 4를 사용하고 있으며 읽기를 선호합니다.프로세스 교체,관로및 기타 주제현재 Bash 매뉴얼. 현재 버전의 macOS에는 Bash 3이 함께 제공됩니다.

2 표준 에러파일이나 장치 유형에 관계없이 거의 항상 버퍼링되지 않습니다. 프로그램이 파일 설명자 2에 대한 쓰기를 버퍼링할 수 없다는 규칙은 없지만 오류 및 경고 메시지가 발생할 때 실제로 확인하고 볼 필요가 있기 때문에 그렇게 하지 않는 강한 전통이 있습니다.별말씀을요, 프로그램이 적절하게 닫히지 않거나 열린 파일 설명자를 플러시하지 않고 비정상적으로 종료되는 경우에도 마찬가지입니다. 이는 일반적으로 프로그램이 기본적으로 표준 오류에 대한 쓰기를 버퍼링하는 버그입니다.

3 프로세스 대체 사용명명된 파이프, 또한 ~으로 알려진선입선출, 이는 셸의 파이프 연산자와 동일한 일반 목표를 달성 |하지만 더 일반적입니다. 그러나 그럼에도 불구하고파이프이다, 나는 그렇게 생각하지 않는다파이프라인, 내 생각에는 쉘의 특정 구문 구조와 해당 동작을 참조하는 것 같습니다.

4 네임드파이프를 파일로 취급한다면,당신은해야, 그렇다면 이것이 실제로 일어나고 있는 일입니다.

5"$COMMAND" 에 등장 하지만너의 답전체 명령을 단일 인수로 전달합니다 script(왜냐하면큰따옴표막다분사), 다음 명령을 전달할 수 있습니다.script 여러 매개변수로.

6 과 마찬가지로리눅스브루, 인정해야겠어당신은 나에게 소개.

7 그러나 민감한 데이터를 비밀로 유지하기 위해 이 동작에 의존하는 사람은 누구나 script자신의 명령 동작을 테스트하고 결과 TypeScript를 확인하여 보호해야 할 데이터가 없는지 확인하는 것이 좋습니다. 추가 보안을 위해 일반적으로 화면에 숨겨진 문자를 표시하는 편집기를 사용하거나 cat -v.

#!/usr/bin/perl표시된 구현을 포함하여 8 과 함께 제공되는 버전은 colorhi대부분의 시스템에서 실행되고 올바른 작업을 수행해야 합니다. 나는 #!/usr/bin/env perl그것을 내 자신의 테스트에 사용했습니다. 그런데 내 친구는 당신과 같은 OS를 사용하고 있습니다(원본 포스터) #!/usr/bin/perl. 이는 시스템에서 제공하는 Perl이 최소한의 복잡성이나 잠재적 의심으로 작동하는지 확인하는 목표를 달성합니다.

9FreeBSD에는 가장 엄격한 의미에서 시스템이 제공하는 Perl이 없습니다. 먼저 설치된 버전을 테스트했습니다 pkg.

답변2

#!/usr/bin/env expect
package require Tcl 8.5
if {[llength $argv] == 0} {
    puts stderr "Usage: $argv0 logfile command \[cmd-args ..]"
    exit 1
}
set ::argv [lassign $::argv thelogfile]
log_file $thelogfile
spawn -noecho {*}$argv
interact

모든 내용은 지정된 로그 파일에 추가되어야 하며( 기본적으로 log_file기록됨 ) 생성된 명령을 조작할 수 있습니다. 사용 예:expect(1)interact

$ rm out
$ ./yointeract out sh
$ echo hi
hi
$ printf "\033[10Ghi\n"
         hi
$ exit
$ xxd out
00000000: 2420 6563 686f 2068 690d 0a68 690d 0a24  $ echo hi..hi..$
00000010: 2070 7269 6e74 6620 225c 3033 335b 3130   printf "\033[10
00000020: 4768 695c 6e22 0d0a 1b5b 3130 4768 690d  Ghi\n"...[10Ghi.
00000030: 0a24 2065 7869 740d 0a                   .$ exit..
$ 

PS 이것은 이 프로그램이 하는 일과 거의 비슷 autoexpect(1)합니다.expect(1)

답변3

     @EliahKagan과 많은 대화를 나눈 후 그는 제가 다음과 같은 결론을 내리는 데 도움을 주었습니다.

먼저 다음 전제 조건을 수집합니다.

  • 분명히 표준 출력과 오류를 사용하여 명령을 실행하고 싶을 것입니다 "$COMMAND".
  • 로그를 첨부할 파일(해당 로그를 생성한 원인을 설명하는 설명을 파일 상단에 남길 수 있도록 하기 위함입니다. 적어도 저는 그렇게 기록하는 경향이 있습니다.) 다음에서 이를 참조하겠습니다. 처럼 "$LOG_FILE".
  • 비교적 새로운 버전을 설치하세요진주(아니요진주6,지금 바로아니요이전 주요 언어 버전과 호환됩니다(아직 없는 경우).
  • @dewtell이 제공한 Perl 스크립트의 실행 가능한 사본그의 대답도착하다이것은 또 다른 Unix & Linux Stack Exchange 질문입니다.. 다음에서는 이를 이라고 지칭하겠습니다 "$RM_ANSI_ESC_SEQS_SCRIPT".
  • 설치하다더 많은 유틸리티(을 위한 sponge.)

"$PATH"귀하의 쉘(나는 그것을 사용하고 있지만 bash다른 쉘은 여기에 설명된 프로세스에 완벽하게 적합할 수 있으므로 이 지침을 거의 또는 전혀 변경할 필요가 없음)이 Perl 및 기타 유틸리티를 찾을 수 있도록 쉘을 수정하십시오 . script이 답변에 언급된 또 다른 명령인 는 적어도 나와 같고 컴퓨터에서 상대적으로 새로운 버전의 OS X/macOS를 실행하는 경우 시스템에서 이미 사용할 수 있어야 합니다. 그렇지 않거나 어떤 이유로든 다른 소스에서 최신 버전을 설치하려면 문제를 해결하거나 지금 설치하십시오.
     그런 다음 다음 명령을 순서대로 실행하십시오.

script -aq "$LOG_FILE" "$COMMAND" # Add the `k` option, either separately or as part of the group of short options already given to this command, if you want to log user input as well.  
"$RM_ANSI_ESC_SEQS_SCRIPT" "$LOG_FILE" | sponge "$LOG_FILE"

또한 이 명령의 일부 버전에는 script구문이 다릅니다.제공된 버전은 OS X/macOS용입니다.이므로 필요에 따라 조정하세요. 그 외에는 그게 다입니다. 그러나 이 모든 것을 하나의 파이프로 연결하는 방법이 있을 수 있다는 점을 덧붙이고 싶습니다. 하지만 이 글을 쓰는 시점에서는 아직 파악하지 못했습니다. 이를 수행하는 방법에 대한 다른 의견이나 답변도 환영합니다. .

관련 정보