最近在看《高级bash脚本编程指南》,书中提到一种去除c文件中注释的方法,其中一条核心的管道命令是:
sed -e "s%/\*%${WEIRD}%g;s%\*/%${WEIRD}%g" “$1” \
| tr '\377\n' '\n\377' \
| sed -ne 'p;n' \
| tr -d '\n' \
| tr '\377' '\n'
其中 ${WEIRD}代表ascii字符\377,$1是输入进来的文件名。
初一看,百思不得其解,于是打算在终端中分步测试每一步的输出,经过一翻研究,我弄明白了每一行的意思。
测试的过程是这样的:
我首先用vi建立了一个c文件example.c,文件内容如下:
/*
some comments here
*/
void main()
{
some codes here. /* comments */
}
/* comments */
void fun()
{
some codes here.
}
设置变量的值:
[root@www exp]# WEIRD=$'\377'
验证第一步的输出,结果是这样的:
[root@www exp]# cat example.c | sed -e "s%/\*%${WEIRD}%g;s%\*/%${WEIRD}%g" > 2.txt
[root@www exp]# cat 2.txt
�
some comments here
�
void main()
{
some codes here. � comments �
}
� comments �
void fun()
{
some codes here.
}
验证第二步的输出,结果是这样的:
[root@www exp]# cat 2.txt | tr '\377\n' '\n\377' > 3.txt
[root@www exp]# cat 3.txt
� some comments here�
��void main()�{� some codes here.
comments
�}��
comments
��void fun()�{� some codes here.�}�
注意这里只是将\377和\n互换,不是正则表达式匹配。
接下来的第三步是最重要的一步:
[root@www exp]# cat 3.txt | sed -ne 'p;n' > 4.txt
[root@www exp]# cat 4.txt
��void main()�{� some codes here.
�}��
��void fun()�{� some codes here.�}�
很神奇,所有带comments的行都去掉了,奥秘就在于sed的命令p和n。p命令打印一行后,n命令直接用下一行代替该行,因为注释行和非注释行是相间的,所以正好起到了想要的效果。
接下来的两步将代码还原:
[root@www exp]# cat 4.txt | tr -d '\n' > 5.txt
[root@www exp]# cat 5.txt
��void main()�{� some codes here. �}����void fun()�{� some codes here.�}�[root@www exp]# cat 5.txt | tr '\377' '\n' > 6.txt
[root@www exp]# cat 6.txt
void main()
{
some codes here.
}
void fun()
{
some codes here.
}
这就是最后的c文件。
当然,这里只是处理一种最简单的情况,对于复杂的c语言代码,以上过程可能不会有理想的效果。
利用逐文件的管道分析法,可以了解管道的实际运行过程,十分有用。