我想将 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 脚本中结合使用,如下所示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
命令(“制作终端会话的打字稿”)可以捕获屏幕上的所有内容并将其放入日志文件中。但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 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 执行的所有系统调用,并包含用于读取和写入的十六进制转储,然后我们可以使用 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
我可以向你保证,当你完成时,你的意见将会出现。