重定向Shell脚本输出到文件时如何避免tput转义序列?
解决
tput颜色转义序列在重定向时的残留问题 你遇到的这个情况是tput工具的典型行为——它默认会根据TERM环境变量定义的终端类型生成转义序列,但并不会自动检测输出目标是不是交互式终端。当你把输出重定向到文件时,tput依然会生成颜色转义码,因为它不知道自己的输出没到终端上。
和TERM、infocmp的关系
TERM环境变量告诉tput当前终端支持哪些功能(比如颜色、光标移动等),infocmp只是用来查看终端数据库中对应TERM的配置信息,本质上不是问题的根源。- 问题的核心是:
tput不会主动判断输出是否是TTY(终端设备),所以即使输出到文件,它还是会按照TERM定义的终端能力生成转义序列。你提到的“模拟非显示终端”思路是对的,但不需要复杂的模拟,只需要让tput知道当前不需要输出转义序列即可。
Ubuntu 16.04下的具体解决方案
1. 检测输出是否为终端,条件生成颜色
这是最推荐的方法,通过POSIX标准的测试命令[ -t 1 ]判断标准输出(文件描述符1)是否连接到终端,只在终端环境下生成颜色:
colorize_filename() { local filename="$1" # 检查标准输出是否为终端 if [ -t 1 ]; then # 终端环境:生成颜色转义序列 local blue=$(tput setaf 4) local reset=$(tput sgr0) echo "${blue}${filename}${reset}" else # 非终端环境(重定向/管道):输出纯文本 echo "$filename" fi }
这个方法兼容性极强,Ubuntu 16.04默认的bash完全支持,而且不会影响其他依赖TERM的命令。
2. 临时设置TERM为哑终端
如果你不想写条件判断,可以临时将TERM设为dumb(哑终端,不支持任何转义序列),强制tput不生成颜色码:
# 调用函数时临时设置TERM TERM=dumb colorize_filename "myfile.txt" >> file.log
或者在函数内部自动切换:
colorize_filename() { local filename="$1" local original_term="$TERM" # 如果输出不是终端,切换到哑终端 if ! [ -t 1 ]; then TERM=dumb fi local blue=$(tput setaf 4) local reset=$(tput sgr0) echo "${blue}${filename}${reset}" # 恢复原TERM设置 TERM="$original_term" }
3. 关于“模拟非显示终端”
其实不需要用script这类工具模拟非终端环境,上面两种方法已经足够直接高效。script主要用于记录完整的终端会话,在这里属于过度设计。
验证效果
调用函数测试:
- 在终端直接执行:
colorize_filename "test.log",会看到蓝色的文件名。 - 重定向到文件:
colorize_filename "test.log" >> output.log,打开output.log会看到纯文本的test.log,没有任何转义序列。
内容的提问来源于stack exchange,提问作者el-teedee
相关产品推荐
相关产品推荐

