用m4 macros创建文本文件

 

原文链接:

http://ldp.linux.no/linuxfocus/ChineseGB/September1999/article111.html

补充阅读:

http://mbreen.com/m4.html


by John Perr
<johnperr(at)linuxfocus.org>

关于作者:

从1994年便成为了Linux 的使用者.他是 LinuxFocus 的法国成员之一.

目录:

用m4 macros创建文本文件

摘要:

这一教程描述了如何用m4宏处理器简化html文件的维护.




介绍

宏命令语言经常被用于文本编辑器.而多数的文本编辑器已经拥有这样的语言功能.C语言的编译器也为编程者在编译预处理时提供了这一特性.而在维护一些配置文件和管理小型网站时,GNU/m4宏处理器可以有效的减轻工作量.GNU/m4 宏处理器伴随所有的Linux版本发行,成为所有Unix使用者的一个标准.

在下面,我们将向你展示如何运用GNU/m4宏处理器去维护一个小型网站的HTML页面.这个程序将帮助我们确保整个网站的连贯性.当然,对于此我们可以采用多种系统工具实现---那也正是Unix的魅力之所在.

这种技术已经应用于我们所熟悉的sendmail.那是因为使用了由EricAllman所设计的m4 宏组件工具.

GNU/m4 宏处理器并不只局限于文本和HTML文件的编辑,对于想要扩展CPP特性或是想要以其他语言实现与CPP特性同等效果的程序设计者时非常有用的.

定义

宏处理器是一个解释用户定义的命令的程序,宏经常使用于文本管理.如下定义:

define(AUTHOR,`Agatha Christiea.christie@scotland-yard.gov')

被允许在文本的任何地方使用 "AUTHOR"这个词.并且在m4处理后,他将被替换为"AgathaChristie<a.christie@scotland-yard.gov>".当然他还会有很多其它的功能,我们将在下面展示.

一个例子

我们假设我们将要维护一个拥有相同页面但却是不同的语言的网站.而且每一个页面都拥有相同的header和footer以实现页面外观的统一.为了简化并且避免使用浏览器来测试我们的结果,我们的例子将字处理文本内容.这样也同时使得人们只使用lynx这样的工具就可以访问我们的网站.以下是其中一页的HTML代码:

HTML文本

<!-- Start of header -->
<HTML>
<HEAD>
<TITLE>Lynx homepage</TITLE>
<META name="description" content="Site lynx et m4">
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#008000" VLINK="#808080" ALINK="#8080FF">
<TABLE>
  <TBODY>
  <TR><TD align=middle colspan="2">
      <H1>Lynx a fully-featured World Wide Web client for character-cell
displays</H1>
  <TR><TD align="left" valign="top" width="15%">
      <a href="./index-en.html">English</A><BR>
      <a href="./index-fr.html">French</A><BR>
      <a href="./index-es.html">Italian</A><BR>
      <a href="./index-it.html">Spanish</A><BR>
      <a href="./index-de.html">German</A><BR>
      <TD align=left>
<!-- End of header -->

      <P>Links to the current sources and support materials for Lynx are
   maintained at <A HREF="http://www.crl.com/~subir/lynx.html">Lynx
   links</A></P>
      <P> and at the Lynx homepage
      <A HREF="http://lynx.browser.org/">Lynx
      Information.</A></P>
      <P>View these pages for information about Lynx, including new
      updates.</P>

      <P>Lynx is distributed under the GNU General Public License (GPL) without
   restrictions on usage or redistribution.  The Lynx copyright statement,
   "COPYHEADER", and GNU GPL, "COPYING", are included in the top-level
   directory of the distribution.  Lynx is supported by the Lynx user
   community, an entirely volunteer (and unofficial) organization.</P>

<!-- Start of footer -->
</TBODY>
</TABLE>
<HR size="0" noshadow>
<FONT SIZE=-2>
<EM>Page maintained by John Perr.<BR>
Page updated on 25/07/99
- © <A HREF="mailto:webmaster@lynx.browser.org">lynx.browser.org</A>1999
</EM></FONT>
</BODY>
</HTML>
<!-- End of footer -->

以下是浏览的结果:

用 lynx 用 netscape

所有的页面都拥有相同的header和footer式样,只是语言和页面的body部分不同.我们现在将要开始编辑m4宏,他们将被加入我们的HTML文本以替换所有重复性的数据.
在我们接触宏的细节之前,让我们上边这个用到宏的例子:

宏文本:

LYNX_TITRE(Lynx a fully-featured World Wide Web
            client for character-cell displays)
LYNX_ENTETE(Lynx homepage)

      <P>Links to the current sources and support materials
      for Lynx are maintained at
      <A HREF="http://www.crl.com/~subir/lynx.html">
      Lynx links</A></P>
      <P> and at the Lynx homepage
      <A HREF="http://lynx.browser.org/">
      Lynx Information.</A></P>
      <P>View these pages for information about Lynx,
      including new updates.</P>

      <P>Lynx is distributed under the
      GNU General Public License (GPL) without
   restrictions on usage or redistribution.
   The Lynx copyright statement, "COPYHEADER",
   and GNU GPL, "COPYING", are included in the top-level
   directory of the distribution.
   Lynx is supported by the Lynx user community,
   an entirely volunteer (and unofficial) organization.</P>
LYNX_PIED

像这样,编辑HTML页面比较容易并且不会造成HTML标示之间的文本丢失.Assuch, writing HTML pages is simpler and the text is not lost among HTML tags.对于其他语言,比喻进行翻译.法语版将变成:

LYNX_TITRE(Lynx un navigateur en mode console)
LYNX_ENTETE(Un site pour les utilisateurs de lynx)

   <P>Visitez le
   <A HREF="http://lynx.browser.org/">
   site officiel de lynx</A>
   pour plus d'informations sur Lynx,
   y compris les nouvelles mises ?jour.</P>

   <P>Les liens vers les sources de la version
   courante et divers supports pour Lynx sont
   tenus ?jour sur le site
   <A HREF="http://www.crl.com/~subir/lynx.html">
   liens Lynx</A>.</P>

   <P>Lynx est distribue dans le cadre de la lisence GNU
   (General Public License - GPL)
   sans restriction sur son utilisation ni sa distribution.
   Les mentions des droits de reproduction de Lynx, "COPYHEADER",
   et GNU GPL, "COPYING", sont inclus dans la racine de
   l'arborescence de la distribution. Lynx est supporte par
   la communaute des utilisateurs de Lynx, une communaute
   enti鑢ement benevole (et non-officielle).</P>
LYNX_PIED

对于每一种语言,相同的宏LYNX_TITRE, LYNX_ENTETE 和 LYNX_PIED分别携带不同的参数被使用.这三个宏可以实现对HTML文本中的header和footer高效替换.这是这一系统的主要优点:header和footer的定义对于整个站点来说是一致的.假如header和footer的内容需要改变的话,只需要修改宏的定义文件而不再需要修改所有的页面了.

宏的定义

以上为了达到相同的格式我们定义了三个宏.这里是宏的定义文件,内容如下:

divert(-1)
# File mac.css
# Version 1.0 M4 macros for Lynx
#
# A file trans-LANG.m4 is defined for each
# language, based on the french one.
# If no translation file exist,
# french is the default.
#
divert(0)
changequote({,})dnl # change quotes to curly braces
ifdef({LANG},,{define({LANG},{fr})})dnl # Default= french
include({trans-}LANG{.m4})dnl	  # call translation file
undefine({format})dnl		  # Suppress the format definition
define({_ANNEE_},esyscmd(date +%Y))dnl 	  #Current year
define({LYNX_TITRE},{define(_TITLE_,$1)})dnl # First macro
dnl # Second macro
define({LYNX_ENTETE},{<!-- Header start -->
<HTML>
<HEAD>
<TITLE>$1</TITLE>
<META name="description" content="Site lynx and m4">
<META name="keywords" content="m4, lynx, GPL">
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#008000" VLINK="#808080" ALINK="#8080FF">
<TABLE>
  <TBODY>
  <TR><TD align=middle colspan="2">
      <H1>_TITLE_</H1>
  <TR><TD align="left" valign="top" width="15%">
      <a href="./index-en.html">_ANGLAIS_</A><BR>
      <a href="./index-fr.html">_FRANCAIS_</A><BR>
      <a href="./index-es.html">_ESPAGNOL_</A><BR>
      <a href="./index-it.html">_ITALIEN_</A><BR>
      <a href="./index-de.html">_ALLEMAND_</A><BR>
      <TD align=left>
<!-- end of header -->})dnl
dnl # Third macro
define({LYNX_PIED},{<!-- Start of footer -->
</TBODY>
</TABLE>
<HR size="0" noshadow>
<FONT SIZE=-2>
<EM>_MAINTENEUR_.<BR>
_MAJ_
esyscmd(date +%d/%m/%y)
- &copy <A HREF="mailto:webmaster@lynx.browser.org">
lynx.browser.org</A>
_ANNEE_</EM></FONT>
</BODY>
</HTML>
<!-- End of footer -->})dnl

解释

在"divert(-1)"和"divert(0)"之间的内容是注释,"Divert"是m4处理器的内置宏.他指向处理程序的输出.使用参数-1,告诉处理程序不向最终的HTML文件写入下面的内容,这也是我们所希望的.

宏"changequote"重新定义经常被引用的宏参数.他们将在此被替换为花括号({}),这是因为在文本中,特别是法语文本中这种引用会被广泛的使用而与宏之间产生误解.花括号({})在文本或是HTML文件中很少使用,这也是为什么我们选择了花括号({}).

宏"ifdef"用于测试宏LANG是否已经被定义了并且将他置为"fr".宏LANG被用于设定语言.在以下的几行中,我们将看到为了选择HTML页面的语言,如何在呼叫m4的时候定义.

与在C语言中的意义相同include开头的几行由来包含一个外部文件.我们使用它来载入宏所定义的在header和footer中所使用的语言.下面是它的内容所对应的语言:

divert(-1)
# File trans-fr.m4
# Definitions for french
divert(0)
define({_ANGLAIS_},{Anglais})dnl
define({_FRANCAIS_},{Fran鏰is})dnl
define({_ITALIEN_},{Espagnol})dnl
define({_ESPAGNOL_},{Italien})dnl
define({_ALLEMAND_},{Allemand})dnl
define({_WEBMASTER_},{John Perr})dnl
define({_MAINTENEUR_},{Page maintenue par _WEBMASTER_})dnl
define({_MAJ_},{Date de mise à jour:})dnl
divert(-1)
# File trans-en.m4
# Definitions for english
divert(0)
define({_ANGLAIS_},{English})dnl
define({_FRANCAIS_},{French})dnl
define({_ITALIEN_},{Spanish})dnl
define({_ESPAGNOL_},{Italian})dnl
define({_ALLEMAND_},{German})dnl
define({_WEBMASTER_},{John Perr})dnl
define({_MAINTENEUR_},{Page maintained by _WEBMASTER_})dnl
define({_MAJ_},{Page updated on })dnl

如果你使用的是西班牙语,意大利语和德语,你可以写出相识的对应于这些语言的文件.

"undefine"禁止了在这里不用的内置的"format".除非已经被引用(用{}包围起来)如果这一行被省略,在这个文本文件中"format"每次出现时将会消失.在设计一个小型网站时,这样做是不可取的.

接下来是对现在所在的年份的定义,这是由宏"easyscmd"所得到的,"easyscmd"呼叫Unix的系统命令date.这个命令也在需要在header和footer中打印出页面更新日期的时候被使用.

接下来的一行定义了我们的主要的三个宏中的第一个: LYNX_TITRE.这个宏定义了另外一个叫_TITRE_ 的宏.为了在页面的header和footer中多次使用一个声明这是必要的.请注意$1 的作用是指向宏的第一个参数.

剩下的段落是定义另外两个主要的宏:LYNX_ENTETE 和 LYNX_PIED.他们分别对应于页面中(除变量)header和footer中的内容.它们是:

  • 要从翻译文件中翻译过来的文字.
  • 在编辑页面时可能修改的内容,如:日期和管理员.

在这一行末尾所出现的"dnl"是一个m4的内置的宏,意思是"删除至新的一行".有了"dnl" m4就不会在解释宏的时候产生一个空行.

创建页面

现在我们的系统已经设置完毕,下面的命令将从这些文件生成主页页面.

    m4 -DLANG=XX mac.css index-XX.m4 > index-XX.html

"XX" 是对于各种语言的代码.请注意这里应用了选项 -D ,类适于C语言的gcc,从命令行定义了一个宏.

总结

下表提供了在这个例子中的文件和它们的作用.

下面的文件用于生成HTML页面:

index-XX.html 页面的主体,这是由作者或是由翻译者所写的.对于每个页面和每种语言其内容是不同的(对于英语代码是 XX=en ,对于西班牙语代码是 XX=es 等等).
mac.css 包含了标准的定义.对于所有的页面,所有的语言这个文件是共同的.可以被看作是定义了某种页面风格的文件.
trans-XX.m4 对每一种语言的标准定义.这个文件对于一种语言的所有页面是共同的.(对于英语代码是 XX=en ,对于西班牙语代码是 XX=es 等等).

结论

尽管它的作用很明显,m4处理程序不可能与其他的脚本语言相比,如PerlTcl.但一旦你了解到它的特性,便是一个处理文本文件快速而且唾手可得的工具.你可以从操作系统的文档中得到更多的参考.你可以找到一个大约30页的m4教材,其中包括了GNU/m4宏处理程序的所有方面.你同时也可以访问一下波尔多Linux俱乐部(ABUL),这个站点就是用m4宏进行维护的,与我们今天的例子非常相识.

连接

可以从 ftp://prep.ai.mit.edu/pub/gnu/m4-1.4.tar.gz得到GNU/m4
下载以上的文件: The Lynxm4 macro kit

感谢 Paul Kienzle审阅这篇文章.

用m4 macros创建文本文件的更多相关文章

  1. [Xcode 实际操作]七、文件与数据-(3)创建文本文件、属性列表文件、图片文件

    目录:[Swift]Xcode实际操作 本文将演示如何创建各种类型的文件. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKit class V ...

  2. 为毛无法创建文本文件COM1.txt

    是的,windows系统下,右键,新建文本文件,将文件名编辑为COM1.txt,确认,保存……THEN....你会发现无论如何也无法创建一个文本文件,名为COM1.txt. 猜是COM1被作为了IO设 ...

  3. bat批处理以当前时间创建文本文件

    :: 表示注释 :: @表示不显示当前命令,只在后台执行 :: @echo off 表示以后执行的命令都不显示 :: set d=%,% 表示设置变量d为当前年月日,默认表示为例如:// :: set ...

  4. C#学习笔记(22)——C#创建文本文件txt并追加写入数据

    说明(2017-7-31 16:25:06): 1. 有两种办法,第一种是用FileStream创建txt,用StreamWriter写入数据,期间还要加上判断,是否存在这个txt文件,如果不存在就创 ...

  5. Linux下创建文本文件(vi/vim命令使用详解)

    vi test.txt 或者 vim test.txt vim是vi的升级版,指令更多,功能更强. 下面是收集的vim用法,当在vim里面要实现退出,首先要做的是按[Esc],然后再输入[:wq] 一 ...

  6. 【Linux】使用cat命令创建文本文件

    在Linux界面输入 Linux:/usr/test # cat >test01.sh 接着按回车,输入内容:"echo hello world !" 回车后按 ctrl+d ...

  7. Mac OS X 在 Finder 里快速创建文本文件

    Automator 新建一个 Application   选取:应用程序 实用工具→运行AppleScript 添加一个动作 "Run AppleScript"代码如下: on r ...

  8. [python]创建文本文件,并读取

    代码如下: # coding=gbk import os fname = raw_input("Please input the file name: ") print if os ...

  9. 如何将cmd中命令输出保存为TXT文本文件

    在使用Windows 中的cmd.exe工具时,有时候我们想要把我们的输入命令及结果保存起来, 但是用复制的方法过于麻烦:有时输出数据条数过大,会造成内容自动滚出屏幕,无法阅读,我们可将命令运行的结果 ...

随机推荐

  1. android NDK的下载-文件太大

    需要FQ,建议使用VPN,下载前准备点时间配置网络环境.我的百度网盘好像有~~不过忘记地址了,改天共享,或者私聊我. 2015.4 Android 5.1 Android Studio https:/ ...

  2. 聚沙成塔-linux 常用命令

    批量更改文件后缀名 find . -depth -name "*.scss" -exec sh -c 'mv "$1" "${1%.scss}.les ...

  3. GC对象分配规则

    1.对象优先分配在Eden区,如果Eden区没有足够的空间时,虚拟机执行一次Minor GC. 2.大对象直接进入老年代(大对象是指需要大量连续内存空间的对象).这样做的目的是避免在Eden区和两个S ...

  4. [boost][filesystem] 扫描给定目录下所有项

    Intro. Boost的filesystem可以用来扫描给定目录下的所有项. 实现 具体实现代码如下: 需要包含的头文件和使用的命名空间: #include <boost/filesystem ...

  5. 剑指Offer——知识点储备-操作系统基础

    剑指Offer--知识点储备-操作系统基础 操作系统 操作系统什么情况下会出现死锁? 产生死锁的必要条件 (1)互斥条件:即某个资源在一段时间内只能由一个进程占有,不能同时被两个或两个以上的进程占有, ...

  6. TCP协议的性能评测工具 — Tcpdive开源啦

    Github地址:https://github.com/fastos/tcpdive 为什么要开发Tcpdive 在过去的几年里,随着移动互联网的飞速发展,整个基础网络已经发生了翻天覆地的变化. 用户 ...

  7. activiti节点跳转

    分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519) activiti使用的时候,通常需要跟业务紧密的结合在一起,有些业 ...

  8. 集合框架之Collection接口

    Collection 层次结构中的根接口.Collection表示一组对象,这些对象也称为 collection 的元素.一些 collection 允许有重复的元素,而另一些则不允许.一些 coll ...

  9. 13 SQLiteOpenHelper SQLiteDatabase详解

    创建数据库: 1. 创建一个类继承SQLiteOpenHelper 2. 创建继承对象 new SQLiteOpenHelper() 3. 用创建的对象获取可写或者可读的SQLiteDatabase ...

  10. Description Resource Path Location Type AndroidManifest.xml file missing!

    这个问题又找了好久.国内回答的确不敢恭维. 本回答来自谷歌:   This is build issue. Go to Menu in eclipse, Project>clean then P ...