모든 쉘 스크립트 출력을 터미널과 로그 파일에 *더하기* 사용자가 입력한 텍스트로 보내는 방법이 있습니까?

모든 쉘 스크립트 출력을 터미널과 로그 파일에 *더하기* 사용자가 입력한 텍스트로 보내는 방법이 있습니까?

쉘 스크립트의 출력(사용자가 입력한 텍스트 포함)을 터미널과 로그 파일로 보내고 싶습니다.

tee나는 와 의 어떤 조합이 트릭을 수행할 수 있다고 생각 exec하지만 지금까지는 운이 없었습니다. tee사용자가 터미널에 입력하는 내용을 자체적으로 에코하고 캡처할 수 있다는 것을 알고 있습니다 .

$ tee logfile
Hello  (I entered this at runtime)
Hello  (I entered this at runtime)
^C

$ cat logfile
Hello  (I entered this at runtime)

하지만 쉘 스크립트에서 호출된 명령에 대한 응답으로 사용자가 입력하는 내용을 터미널과 로그 파일 모두에서 확인해야 합니다.

tee지속적으로 할 수는 없을 것 같습니다.

예를 들어:

$ read message 2>&1 | tee logfile
Hello  (I entered this at runtime)

$ cat logfile

거기에는 아무것도 포착되지 않았습니다. Hello (I entered this at runtime)예전처럼 파일로 볼 수 있었으면 좋겠습니다 .

또한 다음과 같은 쉘 스크립트로 결합해 보았습니다 tee.exec

$ cat test.bash
#!bin/bash
# Note: in this simplified version of this file, I’m not looking at $1, $2, or anything else passed in, but will need to eventually

rm -f logfile
exec &> >(tee -a logfile)
echo “Say \”Hello\”” 2>&1
read -p “> “ 2>&1

불행히도 추가 exec:

$ ./test.bash
Say “Hello”
> Hello  (I entered this at runtime)

$ cat logfile
Say “Hello”
> 

echo보시다시피, 명령과 명령의 출력은 캡처 read하지만 명령에 대한 응답으로 터미널에 입력한 내용은 캡처하지 않습니다 read.

그것을 할 수 있는 방법이 있나요?

나는 script명령("make typescript of Terminal session")이 화면의 모든 것을 캡처하여 로그 파일에 저장한다는 것을 알고 있습니다. 그러나 script명령은 쉘 스크립트에서 유용한 방식으로 호출될 수 없습니다. (그럴 수 있나요?)

script먼저 호출해야 하며, 그런 다음 사용자는 필요한 쉘 스크립트를 호출해야 합니다. 하지만 나는 사용자가 명령과 해당 인수를 호출하고 해당 명령이 다른 모든 것을 실행하고 모든 것을 기록하도록 하길 원합니다.

그러면 스크립트에서 캡처한 모든 "추가" 정보(예: 색상 코드, 백스페이스 키)로 인해 텍스트 편집기에서 결과 로그 파일을 읽기가 어렵습니다.

로그 파일에서 "사람이 읽을 수 있는" 문자를 보고 싶습니다. 사용자가 철자 오류를 수정했는지 확인하고 싶지 않습니다. 편집을 마치고 Enter 키를 눌렀을 때 "Hello"가 화면에 나타나는 것을 보고 싶습니다. 캡처 후 추가 정보가 제거될 수 있다고 생각합니다.

답변1

script최소한 구현은 util-linux스크립트 가능합니다.

예를 들어 다음과 같이 할 수 있습니다.

SHELL=/bin/sh script -qec '
  # any sh code here
  echo Whatever
  cat # user input' file.log

file.log다음을 포함하여 터미널에 기록된 모든 내용을 캡처 합니다 .에코당신이 입력한 것. 여기에는 LF에서 CRLF로의 변환과 같은 tty 라인 규칙에 의해 수행되는 변환도 포함됩니다.

script또한 일부 추가됨

Script started on 2021-09-29 14:58:59+01:00 [TERM="screen.xterm-256color" TTY="/dev/pts/8" COLUMNS="191" LINES="54"]

헤더 및:

Script done on 2021-09-29 14:58:59+01:00 [COMMAND_EXIT_CODE="0"]

바닥글은 ksh 스타일 프로세스 교체 지원을 통해 셸에서 제거됩니다. 다음을 사용하여 제거할 수 있습니다.

SHELL=/bin/sh script -qec '...' >(sed '1d;$d' > file.log)

또는 @zevzek이 제안한 대로 script헤더/바닥글을 포함하여 로그에 기록하도록 지시 /dev/null하고 script출력( -q머리글이나 바닥글 없이)을 tee로깅으로 리디렉션합니다.

(set -o pipefail; SHELL=/bin/sh script -qec '...' /dev/null | tee file.log)

zsh또는 on을 사용하여 multi_ios(기본적으로):

SHELL=/bin/sh script -qec '...' /dev/null >&1 > file.log

의사 tty 시작에 대한 tty 행 규칙에 의한 출력 사후 처리를 비활성화하려면 script다음과 같이 최소한 호스트 tty에서 이를 비활성화하고 NL -> CRNL 변환을 다시 활성화할 수 있습니다.

SHELL=/bin/sh HOST_TTY="$(tty)" script -qec '
  stty -opost && stty < "$HOST_TTY" opost onlcr || exit
  ...' file.log

( 의 명령이 ...이 출력 처리를 복원하지 않는다고 가정합니다.)

답변2

애플리케이션이 tty 장치에 읽고 쓰는 내용을 기록하는 또 다른 방법은 strace -P "$(tty)"tty에 대한 모든 시스템 호출을 기록하고 읽기 및 쓰기에 대한 16진수 덤프를 포함하는 것입니다. 그런 다음 xxd를 사용하여 디코딩할 수 있습니다.

strace -f -e read=all -e write=all \
       -e trace='read,write' \
       -P "$(tty)" \
       -e status=successful -o '|
          grep "^ "|cut -b11-60 | xxd -p -r > file.log
       ' -qqs0 -a0 cat

답변3

사용tee이 구문을 사용하십시오.

read message
echo "${message}" | tee file

file귀하의 의견이 완료될 때까지 귀하의 의견이 거기에 있을 것이라고 보장할 수 있습니다.

관련 정보