终端中的格式与 .txt 文档中的格式不同

终端中的格式与 .txt 文档中的格式不同

我有一个跟踪时间的脚本。

当我在控制台中打印输出时,我得到以下信息:

0 Days, 00:00:33

当我将其保存到 txt 文件时,我得到以下信息:

^[[2K
  0 Days, 00:00:33

代码:

now=$(date +%s)
diff=$(($now - $begin))
mins=$(($diff / 60))
secs=$(($diff % 60))
hours=$(($diff / 3600))
days=$(($diff / 86400))

printf "\33[2K\r%3d Days, %02d:%02d:%02d" $days $hours $mins $secs
printf "\33[2K\r%3d Days, %02d:%02d:%02d" $days $hours $mins $secs >> test.txt

是从哪里来^[[2K的?我猜这与 printf 中的格式有关。

我在这里读了一些关于 printf 的内容:http://wiki.bash-hackers.org/commands/builtin/printf。但我并没有变得更明智......

答案1

printf您的命令中有转义控制序列printf "\33[2K.....,即(\e[2K清除一行),这必然是终端的控制命令,只能由终端设备理解和执行。

当您在终端内以交互方式运行脚本时,终端会正确解释该序列。将命令的输出保存在文件中时,会按字面意思处理序列,因为此时没有任何内容可以解释该序列。

现在如果你这样做:

cat test.txt

您会看到终端在打印输出之前再次正确解释序列。

答案2

线条的连续性

printf "\33[2K\r%3d Days, %02d:%02d:%02d" $days $hours $mins $secs
printf "\33[2K\r%3d Days, %02d:%02d:%02d" $days $hours $mins $secs >> test.txt

被定义为打印时间信息同一条线一个终端的。那\33[2K清除整个(当前)行,并且\r将光标移至行首。效果是让改变的时间信息,只是看起来改变了线的一部分。

我注意到没有换行符(\n)的格式。该问题显示了换行符(也许是为了清楚起见而添加了换行符)。

答案3

你自己写的,如

\33[2K

根据您的终端,它会将其理解为执行某些操作的指令。既然您提到了“控制台”,您可以查阅console_codes(4)手册页,其中列出了:

ECMA-48 CSI 序列

CSI (或 ESC [) 后面最多是一系列参数国家公园管理局(16),是用分号分隔的十进制数。空或不存在的参数被视为 0。参数序列前面可以有一个问号。

...

K: EL - 擦除线

默认值:从光标到行尾。
ESC [ 1 K:删除从行首到光标处的内容。
ESC [ 2 K:删除整行。

(这有助于回忆\033与 相同ESC)。

因此,您的转义序列是对该终端的“擦除整行”命令。

编写此代码的可移植(且更清晰)的方法是

clear_line=`tput cr; tput el`
printf "${clear_line}%3d Days, %02d:%02d:%02d" $days $hours $mins $secs

使用tput意味着当写入不支持该el操作的终端或使用不同转义序列支持该操作的终端时,您将获得适当的输出,而不是难以理解的垃圾。


PS 假设 GNU ,所有这些算术可能都是不必要的date。如果你不超过 7 天,你可以把它减少到

date -u -d "-$begin seconds +3days" '+${clear_line}%w days, %T'

否则,您仍然需要计算$days,但您可以使用以下格式格式化秒%T

now=$(date +%s)
diff=$(($now - $begin))
days=$(($diff / 86400))
date -u -d "00:00 $diff seconds" '+${clear_line}$days days, %T'

相关内容