我正在尝试将 bash 的所有输出(提示符、用户输入、结果)重定向到文件
例子:
/bin/bash > file.txt 2>&1
我以为这会起作用,但我没有收到提示。谁能告诉我我做错了什么?
答案1
Bash 仅在交互模式下输出提示符。即它通常输出到终端(Linux 上的 /dev/tty)。那既不是 /dev/stdout 也不是 /dev/stdin :)
现在,我不确定,但我可以想象,当没有功能齐全的 tty 时,bash 将允许有限的交互模式。在那种情况下我会预计要写入标准输出的提示。我还没有测试过。
很好的概念证明:
(for a in some set of words; do echo $a > /dev/tty; done) 2>&1 > /dev/null
将仅输出 1..10,就好像没有重定向一样。和提示符一样,直接将输出发送到终端(没有终端就会失败)
提示:如果您想收集所有内容,请查看
- 脚本(1)与脚本重播(捕获SSH客户端中的执行日志?或者脚本shell录音回放- 这似乎是一个常见问题解答)
- 这PROMPT_COMMAND 变量这应该允许您将内容打印到标准输出,作为显示提示的副作用
set -o xtrace
(又名set -x
等bash -x
)用于一般日志记录声明
答案2
最简单的方法是
bash -i >/tmp/logfile 2>&1
当您键入命令时,Bash 会将所有内容写入/tmp/logfile
并继续执行命令,但终端中不会显示任何内容。您可以在退出终端会话时使其退出 - 通过按Ctrl+D或键入exit
。
请注意,如果您在没有重定向的情况下运行相同的操作stderr
,则只会将问候消息记录到文件中,其余所有内容都将在当前终端中运行。因此,关于 bash 输出其提示符(以及所有以下命令)的流的问题的答案似乎是:标准错误。
哦,是的,该-i
参数只是强制 bash 以交互模式运行。不要听那些人的话 - 你不需要任何魔术来做到这一点;)
答案3
提示符被写入 stderr,如 truss(此处在 Solaris 上)所示:
$ truss -ft write -p 10501
10501: write(2, " d", 1) = 1
10501: write(2, " a", 1) = 1
10501: write(2, " t", 1) = 1
10501: write(2, " e", 1) = 1
10501: write(2, "\n", 1) = 1
10521: write(1, " S a t u r d a y , S e".., 46) = 46
10501: Received signal #18, SIGCLD [caught]
10501: siginfo: SIGCLD CLD_EXITED pid=10521 status=0x0000
10501: write(2, " $ ", 2) = 2
答案4
在交互模式下,bash 将其提示符输出到 stderr。以下 strace 命令显示了它(--norc
确保设置另一个提示的 ~/.bashrc 的选项不会被解释为覆盖我的自定义提示):
$ export PS1="MYPROMPT> "
MYPROMPT> strace -f -- bash --norc
execve("/usr/bin/bash", ["bash"], 0x7ffcd83805b0 /* 59 vars */) = 0
[...]
openat(AT_FDCWD, "/dev/tty", O_RDWR|O_NONBLOCK) = 3
[...]
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(2, TCGETS, {B38400 opost isig icanon echo ...}) = 0
[...]
write(2, "MYPROMPT> ", 10MYPROMPT> ) = 10 <----- prompt written into stderr (fd = 2)
pselect6(1, [0], NULL, NULL, NULL, {[], 8}
将 stdout 和 stderr 重定向到文件中的相同命令显示未打印提示符,但 shell 接受命令:
MYPROMPT> strace -f -- bash --norc > /tmp/shout 2> /tmp/sherr
date
从另一个终端查看文件。内容为喊是:
$ cat /tmp/shout
dim. 04 sept. 2022 16:19:24 CEST <------- Result of the date command entered above
内容为谢尔是:
$ cat /tmp/sherr
execve("/usr/bin/bash", ["bash", "--norc"], 0x7ffe73ea5da8 /* 59 vars */) = 0
[...]
openat(AT_FDCWD, "/dev/tty", O_RDWR|O_NONBLOCK) = 3
[...]
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(2, TCGETS, 0x7ffc43496b30) = -1 ENOTTY (Inappropriate ioctl for device)
[...]
read(0, <-------- No prompt is displayed
但是如果您-i
对 bash 命令行执行相同的添加选项:
MYPROMPT> strace -f -- bash --norc -i > /tmp/shout 2> /tmp/sherr
stderr 上显示提示:
$ cat /tmp/sherr
execve("/usr/bin/bash", ["bash", "--norc", "-i"], 0x7ffd8c1fa520 /* 59 vars */) = 0
[...]
ioctl(2, TCGETS, 0x7ffe1a8465f0) = -1 ENOTTY (Inappropriate ioctl for device)
[...]
ioctl(0, TIOCGWINSZ, {ws_row=37, ws_col=155, ws_xpixel=0, ws_ypixel=0}) = 0
[...]
write(2, "MYPROMPT> ", 10MYPROMPT> ) = 10 <------ Prompt displayed on stderr (fd = 2)
pselect6(1, [0], NULL, NULL, NULL, {[], 8}