日志打印是软件必需的功能,通常C程序会将所有运行日志输出到指定LOG。
一、有时候需要在C程序运行期间查看实时日志,最好地,可以根据关键字筛选自己想要查看的内容。
二、有时候,希望另开Terminal去查看日志,而不是使用当前的Terminal。
实时筛选流,利用tail命令可以实现,流显示则可以用tee命令;Linux设备自启Terminal窗口,利用gnome-terminal命令实现(在gnome集成桌面环境)。
关于tail命令
tail -f filename 会把 filename 文件里的最尾部的内容显示在屏幕上,并且不断刷新,只要 filename 更新就可以看到最新的文件内容。
关于tee命令
tee指令会从标准输入设备读取数据,将其内容输出到标准输出设备,同时保存成文件。
关于gnome-terminal命令
如果想在启动Terminal中自动执行命令,有两个参数可以实现这个功能,-e和-x(或者"--"),这两个区别在于:
"-e"可以出现多次,如果在所有--window前面,表示对所有window和tab起作用,如果在--window或者--tab后面,表示只针对这个tab执行,要注意-e后面只能有一个参数也就是说如果有空格,需要用引号(-e选项会被提示不适用,后面版本可能移除)。
"-x"只能出现一次,在-x后面的所有内容,均认为是要执行的命令,所以可以出现空格,这些命令是针对所有tab都执行的。
如果C程序直接将日志打印到屏幕,那么可以使用重定向符">"或者">>"将流先重定向到指定LOG文本,然后利用tail命令实时显示到启动的Terminal窗口:
gnome-terminal --title="LOG_PRINT" -- bash -c "tail -f ./test.log"
利用"bash -c"在bash里面再启用一个bash,执行log的分流命令(避免在test.log未增加时新开Terminal闪退)。
对于日志的筛选可以使用正则表达式作为筛选条件或者shell脚本的命令行参数,脚本判断筛选条件之后动态创建多个分流Terminal窗口显示包含指定关键字的日志内容。类似于:
/INFO/p
/ATA*|BTB*/p
“/p” 打印,如果同时指定行,表示打印指定行;如果不指定行,则表示打印所有内容;如果有非打印字符,则以 ASCII 码输出。其通常与“-n”选项一起使用。
利用for循环动态处理分流条件RE,将主日志分流导入到各分日志并显示在窗口:
touch $TESTLOG
for (( i =1; i < $#; i++))
do
RE=$1
eval RE="$"$i
TERMINAL_TITLE=RE_NO."$1"_LOGPRINT
touch $LOGPATH/RE_$i.log
echo "RE_NO.${i}_LOGPRINT display result of regular expression: $RE"
CMD="tail -f $TESTLOG | sed -un \"$RE\" | tee RE_$i.log"
gnome-terminal --title="$TERMINAL_TITLE" -- bash -c "$CMD"
shift
done
fi
另外在这之后新开一个Terminal用于显示所有日志:
gnome-terminal --title="MAIN_LOGPRINT" -- tail -f $TESTLOG
最后考虑执行c程序:
./Test >> $TESTLOG
把C程序执行放到脚本的最后是为了使用CTRL+C可以一键终止C程序的打印,否则将失去对C程序的控制,因为shell脚本默认以脚本最后一个进程接收CTRL+*命令。所以这里执行命令的顺序是重点需要注意的地方,也因此在前面会使用bash命令。
另外,程序输出有两种方式:一种是即时处理方式,另一种是先暂存起来,然后再大块写入的方式,前者往往造成较高的系统负担。因此,c语言默认按块输出。为了让日志可以实时刷新,还需要在C程序中设置输出缓存:
setbuf(stdout, NULL);