将 bash 提示符重定向到文件时出现奇怪的输出

将 bash 提示符重定向到文件时出现奇怪的输出

我将 bash 命令的标准错误重定向到一个文件,并且 bash 提示符也重定向了。但是当我打印文件内容时,它是空的。bash 提示符去哪儿了?

图像

当我再次将 bash 的标准输出重定向到一个文件时,它会重定向输出,而不是预期的提示符,但在打印文件内容时,也会出现提示符中的一些字符。怎么办?

在此处输入图片描述

$PS1 和 $PROMPT_COMMAND 的值:

在此处输入图片描述

答案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;kapilapil\007^G。这没关系。重点是你没有预料到的事情从printf你的 中出现了PROMPT_COMMAND

如果我是你,并且我想保留这个PROMPT_COMMAND,我会将其设置为。通常,交互式 shell 的 stdout 和 stderr 会转到同一个终端,因此打印到哪一个(从 执行)printf … >&2并不重要。但是,当你像你所做的那样重定向 stdout 时,你不希望 出现“垃圾” 。printfPROMPT_COMMANDPROMPT_COMMAND

答案2

由于提示中的二进制字符,重定向将导致文件难以读取(或使用)。

为了获得会话的可读完整副本,你可以使用 脚本(1) 记录发送到终端的所有内容:

$ script
Script started, file is typescript
$ # do your work
...
$ # then exit with ^D
$ exit
Script done, file is typescript

相关内容