我有一个跟踪时间的脚本。
当我在控制台中打印输出时,我得到以下信息:
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'