有没有办法将所有 shell 脚本输出发送到终端和日志文件,*加上*用户输入的任何文本?

有没有办法将所有 shell 脚本输出发送到终端和日志文件,*加上*用户输入的任何文本?

我想将 shell 脚本的输出(包括用户输入的文本)发送到终端和日志文件。

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)

但我需要(在终端和日志文件中)查看用户为响应 shell 脚本中调用的命令而输入的内容。

tee似乎无法始终如一地做到这一点。

例如:

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

$ cat logfile

那里什么也没被捕获。我希望Hello (I entered this at runtime)能像以前一样在文件中看到。

我还尝试在 shell 脚本中结合使用,如下所示teeexec

$ 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命令(“制作终端会话的打字稿”)可以捕获屏幕上的所有内容并将其放入日志文件中。但script无法从 shell 脚本中以有用的方式调用该命令。 (它可以?)

script需要首先调用,然后用户必须调用所需的 shell 脚本。但我希望用户只需调用一个命令及其参数,然后让该命令负责运行其他所有内容并记录所有内容。

然后,脚本捕获的所有“额外”信息(例如颜色代码、退格键)使得在任意文本编辑器中读取生成的日志文件变得困难。

我只想查看日志文件中的“人类可读”字符。我不想查看用户是否更正了拼写错误。我只想看到当他们完成编辑并按 Enter 键时,屏幕上会显示“Hello”。尽管我认为捕获后可以删除额外的信息。

答案1

script至少实现是util-linux可编写脚本的。

例如你可以这样做:

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

并将file.log捕获写入终端的所有内容,包括回声您输入的内容。这还包括 tty 行规则执行的转换,例如 LF 到 CRLF 的转换。

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 中删除,您可以使用以下命令删除:

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)

或者 with with zshon 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 执行的所有系统调用,并包含用于读取和写入的十六进制转储,然后我们可以使用 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我可以向你保证,当你完成时,你的意见将会出现。

相关内容