答案1
bash 2>file
解释
交互式 Bash 确实使用 stderr 来打印提示(以及正在编辑的命令行)。
bash 2>file
不会将任何这些内容保存到文件中,因为它不是交互式的。非交互式bash
不会打印任何提示,不会评估PROMPT_COMMAND
;没有提供的命令行编辑readline
,如果输入来自终端,则只能使用终端驱动程序提供的基本编辑。
虽然《Bash 参考手册》声称“交互式 shell 是启动时不使用非选项参数 […] 并且其输入和输出都连接到终端 […]”,但我的测试表明它与 stdin 和 stdout 无关(正如我对“输入和输出”的解释),而是与 stdin 和 stderr 有关。我的意思是这些启动非交互式 shell:
<script bash
bash 2>file
这些命令启动交互式 shell:
bash >file
bash
当bash 2> file
您启动非交互式 shell 时,bash
没有打印任何提示,这就是为什么文件为空。
如果您bash -i 2>file
这样做了,那么您将强制使用交互式 shell,您将向文件发送提示。尝试一下,但不要期望您输入的内容会得到回显,因为这会发送到文件。
类似地,如果您重定向了已经运行的交互式 bash 的 stderr ( exec 2>file
),那么您也会捕获它的提示符。
bash >file
解释(就你的情况而言)
如上所述,bash >file
启动一个交互式 shell。在终端中可以看到提示,可以编辑命令。Stdout 按照预期重定向。
在您的情况下file
包含额外的字符串,因为您的PROMPT_COMMAND
就是它。
PROMPT_COMMAND
如果设置了此变量,并且它是一个数组,则每个集合元素的值将被解释为在打印主提示符 ($PS1
) 之前要执行的命令。如果设置了此变量但不是数组变量,则其值将用作要执行的命令。
(来源)
这是你的PROMPT_COMMAND
:
printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/\~}"
执行时,它会打印到 stdout。如果 stdout 重定向到文件,它会打印到该文件。
当发送到足够先进的终端(终端模拟器)时,\033]0;…\007
图标名称和窗口标题的更改会产生一个字节序列。换句话说,通常您的终端会截取此输出并使用它来配置自身,而不是打印任何内容。
可能您故意设置了它PROMPT_COMMAND
但忘记了(或者根本没有意识到)它会打印到标准输出。
当 stdout 重定向到常规文件时,将没有终端来拦截序列,并且printf
来自 的PROMPT_COMMAND
打印内容将到达文件。您正是观察到了这一点。它似乎试图对 ESC 字符(来自)和 的第一个字母bat
做些什么,这就是为什么您看到;来自 的 BEL 字符显示为\033
]0;
kapil
apil
\007
^G
。这没关系。重点是你没有预料到的事情从printf
你的 中出现了PROMPT_COMMAND
。
如果我是你,并且我想保留这个PROMPT_COMMAND
,我会将其设置为。通常,交互式 shell 的 stdout 和 stderr 会转到同一个终端,因此打印到哪一个(从 执行)printf … >&2
并不重要。但是,当你像你所做的那样重定向 stdout 时,你不希望 出现“垃圾” 。printf
PROMPT_COMMAND
PROMPT_COMMAND
答案2
由于提示中的二进制字符,重定向将导致文件难以读取(或使用)。
为了获得会话的可读完整副本,你可以使用 脚本(1) 记录发送到终端的所有内容:
$ script
Script started, file is typescript
$ # do your work
...
$ # then exit with ^D
$ exit
Script done, file is typescript