我可以重定向脚本中所有内容的 stdout/stderr,如下所示:
#!/bin/bash
exec > stdout_file
echo example
但现在我希望将整个脚本的标准输入写入文件中。我尝试过这样的:
#!/bin/bash
exec 0>stdin_file
sleep 5
如果我在睡眠运行时输入“foo”,它将不会写入文件,但 bash 将在脚本退出后尝试运行命令“foo”。我认为这是因为 bash 将标准输入连接到 sleep 的标准输入,但 sleep 不从标准输入读取。
我希望所有用户输入都重定向到文件,而不是发送到脚本中命令的标准输入(此处由“睡眠”表示)。
除此之外,我还尝试过
cat - >stdin_file &
但这不起作用,因为 bash 在将其发送到后台时断开了 cats stdin 的连接。
答案1
我不确定您的目标是什么,但尝试进入终端和交互式命令可能会有些棘手。旨在执行此操作的工具是脚本(1),来自 util-linux。
假设您有一个bridge.sh
包含:
#!/bin/sh
read -p "What… is your name? " NAME
read -p "What… is your quest? " QUEST
read -p "What… is your favourite colour? " COLOUR
echo "Go on. Off you go."
您可以使用以下命令捕获终端会话:
script -c ./bridge.sh bridge_script
由于您只对用户的输入感兴趣,因此可以使用:
script -c ./bridge.sh --log-in bridge_input_script
手册页警告:
脚本将所有内容放入日志文件中,包括换行符和退格键。这不是天真的用户所期望的。
事实上,您可以在输入日志中看到我的每个输入末尾都有一个裸露的 CR。 (这是有道理的;我点击了⏎,它记录了 CR。)
> cat -A bridge_input_script
Script started on 2023-05-24 09:46:19-04:00 [TERM="xterm-256color" TTY="/dev/pts/4" COLUMNS="124" LINES="40"]$
My name is Sir Lancelot of Camelot.^MTo seek the Holy Grail.^MBlue.^M$
Script done on 2023-05-24 09:46:32-04:00 [COMMAND_EXIT_CODE="0"]$
(这确实是在不了解更多关于检测下的命令的情况下它能做的最好的事情。)
这是我通常所做的,以确保我拥有未来分析可能需要的所有数据:
script -c ./bridge.sh --log-timing bridge_timing_log --log-io bridge_io_log
我用剧本重播(1)回放会话:
scriptreplay --log-io bridge_io_log --log-timing bridge_timing_log -m 0.01
(因为我不太关心时间,所以我将-m 0.01
最大延迟限制在 10 毫秒。)
script
还有一些更多的技巧,包括脚本直播(1), 哪个实际上重新运行你的会话从日志中。 (你真的可以搬起石头砸自己的脚。RTFM,小心!)
答案2
#! /bin/bash -
tee input.log | {
# contents of your script here
}
将保存标准输入input.log
并将其提供给大括号内的代码。该代码将看到来自管道的输入,如果它期望输入来自 tty 设备,这可能会影响其行为。
您可以使用以下命令保存输入和输出:
#! /bin/bash -
set -o pipefail
tee input.log | {
# contents of your script here
} | tee output.log
(pipefail
以免错过任何一个tee
或代码,但要注意它也会影响管道内的退出状态代码)。