25.2.6 混合C++(www.cppentry.com)使用Perl和shell脚本(1)
C++(www.cppentry.com)包含一个内建的通用机制可以和其他语言和环境接口。您已经使用这种机制很多次了,但是可能没有太注意-- 这就是main()函数的参数和返回值。
C和C++(www.cppentry.com)在设计的时候考虑的是命令行接口。main()函数从命令行接收参数,并且返回一个状态码供调用者解释。在脚本环境中,参数和程序返回的状态码是与环境交互的强大机制。
1. 脚本还是编程(www.cppentry.com)
在深入学习C++(www.cppentry.com)和脚本语言混合编程(www.cppentry.com)之前,首先考虑您的项目是应用程序还是一个脚本。两者之间的区别很微妙,而且存在争论。下面的说明只是指导方针。许多所谓的脚本和成熟的应用程序一样复杂。问题不在于某件事情是否能通过脚本完成,而是脚本语言是否是最合适的工具。
应用程序是完成某一项特定任务的程序。现代应用程序通常涉及某种用户交互。换句话说,应用程序往往由用户驱动,用户指导应用程序应该采取什么操作。应用程序通常具有多种功能。例如,用户可以利用照片编辑应用程序缩放图像、在图像上绘制或打印图像。大部分盒装软件都是一个应用程序。应用程序通常比较大,而且往往是复杂的程序。
脚本通常执行一个任务,或一组相关的任务。您可以通过一个脚本程序自动分拣电子邮件或备份重要文件。脚本通常在没有用户交互的情况下运行,也许是在每天的一个特定时间运行或由事件引发,如新邮件到达。脚本可以在操作系统层次(例如每天晚上压缩文件的脚本),或在应用程序的层次(例如一个自动压缩和打印图像的脚本)。自动化是脚本定义中的一个重要部分-- 编写脚本的目的通常是用代码描述一些用户可以人工完成的步骤。
现在,考虑脚本语言和编程(www.cppentry.com)语言之间的差异。并非所有脚本都必须用脚本语言编写。您可以用C语言编写一个分拣电子邮件的脚本,还可以用Perl脚本语言编写一个相同的程序。同样,并不是所有的应用程序都是用编程(www.cppentry.com)语言编写的。一个有正当动机的程序员可以根据自己的需要用Perl语言编写一个Web浏览器。界线是模糊的。
最后,最重要的是哪种语言提供了您所需要的功能。如果您需要和操作系统做大量的交互,您可以考虑使用脚本语言,因为脚本语言对操作系统交互的支持更好。如果您的项目应用范围更广,而且涉及大量用户交互,那么长久来看,编程(www.cppentry.com)语言是更好的选择。
2. 使用脚本
原始的Unix操作系统包括一个相当有限的C库,这个库不支持一些常用的操作。因此Unix程序员养成了从应用程序中加载shell脚本的习惯,以完成某些API或库不支持的任务。
如今,很多这些Unix程序员仍然习惯使用脚本作为一种子例程调用的形式。他们通常执行C库函数system(),通过一个字符串表示要执行的脚本。这种方法也有重大风险。例如,如果脚本有一个错误,调用者可能会也可能不会得到一个详细的错误提示。system()调用的量级很重,因为这个调用要创建一个新的进程执行脚本。这最终可能成为应用程序中的一个严重性能瓶颈。
通常情况下,您应该探寻C++(www.cppentry.com)库中的特性,看看有没有更适合某个任务的特性。有很多平台无关的包装库封装了很多平台相关的库,例如Boost <filesystem>库。通过system()启动Perl脚本来处理一些文本数据之类的做法可能不是最好的选择。使用C++(www.cppentry.com)11中正则表达式这类技术可能是字符串处理更好的选择。
3. 一个实际的例子:密码加密
假设您有这样一个系统,将用户看到的和输入的所有内容写入文件用作审核的目的。这个文件只有系统管理员才能读取,这样出现了错误之后才能找出是谁的错误。这个文件的摘录看起来像这样:
- Login: bucky-bo
- Password: feldspar
- bucky-bo> mail
- bucky-bo has no mail
- bucky-bo> exit
虽然系统管理员可能希望保存所有用户活动的日志,但是她可能想要掩盖所有用户的密码,以防这个文件被黑客获取。脚本似乎是这个项目的自然之选,因为这个任务应该自动进行,例如在每天结束的时候。然而,这个项目中有一个部分可能不是最适合脚本语言的。加密库常常存在于高级语言中,例如C和C++(www.cppentry.com)。因此,一种可能的实现是编写一个脚本调用C++(www.cppentry.com)程序执行加密。
下面的脚本使用Perl语言,虽然几乎所有的脚本语言可以完成这项任务。如果您不知道Perl,您还是能看懂下面的内容。在这个例子中Perl语法最重要的元素是`字符。`字符告诉Perl脚本执行一个外部命令。在这个例子中,这个脚本将调用一个名为encryptString的C++(www.cppentry.com)程序。
启动一个外部进程会造成很大的开销,因为要建立一个完整的新进程。如果需要频繁调用外部进程则不应该使用外部调用。在这个密码加密的例子中问题不大,因为假设一个日志文件中包含的密码行并不多。
这个脚本采用的策略是循环遍历文件的每一行,寻找包含提示密码的行。该脚本写入一个新的文件userlog.out,这个文件的内容和源文件的内容一致,只不过其中的密码都经过了加密。第一步是打开供读取的输入文件和供写入的输出文件。然后这个脚本要遍历文件中的所有行。接下来每一行都放在一个名为$line的变量中。
- open (INPUT, "userlog.txt") or die "Couldn't open input file!";
- open (OUTPUT, ">userlog.out") or die "Couldn't open output file!";
- while ($line = <INPUT>) {
-
- 代码取自Perl\processLog.pl