Bash 将其提示符写入哪个流?

Bash 将其提示符写入哪个流?

我正在尝试将 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,就好像没有重定向一样。和提示符一样,直接将输出发送到终端(没有终端就会失败)

提示:如果您想收集所有内容,请查看

答案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}

相关内容