为什么我的DEBUG陷阱在{echo foo中执行(内容被重定向);回音棒; }>文件?

时间:2018-01-23 17:01:07

标签: bash

这个组{ echo hello; echo world; }完全按照它在bash shell文件中所说的完成。它输出(od -xa

0000000    6568    6c6c    0a6f    6f77    6c72    0a64
          h   e   l   l   o  nl   w   o   r   l   d  nl
0000014

如果我在.bashrc中定义了以下内容:

show_command_in_title_bar()
{
    case "${BASH_COMMAND}" in
        *\033]O*|*\\e]0*)
            true;;
        my_prompt_command)
            true;;
        *)
            printf "\e]0;%s\a" "${BASH_COMMAND}";;
    esac
}

trap show_command_in_title_bar DEBUG

...我运行以下重定向:

{ echo hello; echo world; } > a

然后文件的内容是:

0000000    5d1b    3b30    6365    6f68    6820    6c65    6f6c    6807
        esc   ]   0   ;   e   c   h   o  sp   h   e   l   l   o bel   h
0000020    6c65    6f6c    1b0a    305d    653b    6863    206f    6f77
          e   l   l   o  nl esc   ]   0   ;   e   c   h   o  sp   w   o
0000040    6c72    0764    6f77    6c72    0a64
          r   l   d bel   w   o   r   l   d  nl
0000052

我不会远程了解发生了什么。使用| od -xa管道同一组显示正确的结果。使用| tee a写入文件也可以。

为什么互动式echo会触发DEBUG

1 个答案:

答案 0 :(得分:3)

默认情况下,DEBUG陷阱已禁用:

  • shell函数
  • 命令替换
  • 在子shell环境中执行的命令

管道在子shell中运行,因此| tee a实例禁用了陷阱。

但是,没有任何子shell的命令分组都不是这三个类别。因此,执行陷阱(并打印您询问的内容)符合正确的记录行为。

我的主要建议不是(ab)使用DEBUG陷阱来达到目的。

我的第二个建议是将用于人类消费的内容指向stderr,或者(甚至更好)/dev/tty - 而不是stdout。因此,该行将成为:

printf '\e]0;%s\a' "${BASH_COMMAND}" >/dev/tty

或者,您可以预先打开指向.bashrc中TTY的文件描述符。如果使用bash 4.1的自动文件描述符分配,那么函数定义后.bashrc中的代码将变为:

# open a file descriptor on the TTY *once*, instead of doing it over and over
# the trailing "||:" prevents this from being an error if it fails
exec {tty_fd}>/dev/tty ||:

# when running the code in the trap, use that file descriptor
# similarly, the ||: means our DEBUG trap never returns false
trap '[[ $tty_fd ]] && show_command_in_title_bar >&$tty_fd ||:' DEBUG