Archive

Archive for August, 2007

用sed替换跨行内容

August 8th, 2007 Fwolf 5 comments

sed是*nix下方便的行编辑工具,经常用来替换文件的内容,sed一般都是处理单行的,但通过它的一些内建功能,也能实现跨行替换(即要替换的内容有多行内容)。

解决方法主要来自网上搜到的一篇文章,但文中的大侠并没有解释得特别清楚,我对照着其他两个更晦涩的例子(),结合man搞懂了之后,记录于此。

假设我们的目标文件test内容是这样的:

file content
  aabbcc<<<comment part 1
  comment part 2>>>
  ddeeff

现在需要把[[[...]]]这一段替换为“COMMENT”(为了说明的必要,没有用容易和正则相混淆的字符比如//*{}[]等来举例子),那么sed语法应当是:

:begin
/<<</,/>>>/ {
    />>>/! {
        $! {
            N;
             b begin
        }
    }
    s/<<<.*>>>/COMMENT/;
}

上述语句存储在test.sed中,那么执行的方式和结果就是:

$ sed -f test.sed test
        file content
          aabbccCOMMENT
          ddeeff

把正则直接写到命令里面也可以,用“;”来分隔命令即可:

$ sed -e ":begin; /<<</,/>>>/ { />>>/! { $! { N; b begin }; }; s/<<<.*>>>/COMMENT/; };" test
        file content
          aabbccCOMMENT
          ddeeff

注意右花括号之后也要加上分号“;”,如果再加上-i参数就可以直接把改动写到原文件中去了。

怎么样?看懂了么?我来详细说明吧,看那个多行命令的test.sed文件的内容:

  • 首先花括号{}代表命令块的开始,类似c的语法,后面就不再说了。

  • :begin,这是一个标号,man中叫做label,也就是跳转标记,供b和t命令用,本例中使用了b命令。

  • /<<</,/>>>/,这是一个地址范围(Addresses),后面{}中的命令只对地址范围之间的内容使用。其中逗号前面的部分是开始地址,逗号后面是结束地址,都是正则表达式。由于sed是“流”式“行”处理,所以结束地址是可以省略的,即如果地址的结束范围不存在,那么将一直处理到文件结尾。本例中使用这个地址范围主要是缩小处理的数据量,因为虽然后面用N命令把对一行的处理扩展为了多行,但如果从文件开头一直N扩展到<<<出现为止,buffer中要处理的字符串可能会很长,影响效率。所以去掉这个处理范围也是能够得到正确结果的,比如:

    $ sed -e ":begin; { />>>/! { $! { N; b begin }; }; s/<<<.*>>>/COMMENT/; };" test
    or
    $ sed -e "{:begin;  />>>/! { $! { N; b begin }; }; s/<<<.*>>>/COMMENT/; };" test
    
  • />>>/!>>>是要替换内容的结束标记,带上!就是说当一行处理完毕之后,如果没有发现结束标记。。。

  • $!$在正则中表示字符串结尾,在sed中代表文件的最后一行,本句和上一句结合起来的意思就是:如果在本行没有发现结束标记,并且当前扫描过的行并不是文件的最后一行。

  • N;,把下一行的内容追加(append)到缓冲区(pattern)之后,在我们的例子中,在处理aabbcc<<<comment part 1这一行的内容时,就会执行到这里,然后把下一行的内容comment part 2>>>一起放入缓冲区,相当于“合并”成了一行(sed的缓冲区中默认都只会包含一行的内容)。

  • b begin,由于仍然没有找到结束标记<<<(注意上一条说的缓冲区还没有被处理),所以在这里跳回到标号begin,重新开始命令。如果开始和结束标记之间间隔了多行,那么就会有多次跳转发生。

  • s/<<<.*>>>/COMMENT/;,终于,/>>>/!不再匹配成功,也就是我们已经找到了结束标记,那么用s命令来进行替换。如果开始和结束标记在一行的话,就会越过上面那些复杂的处理,直接执行到这里了。

介绍完毕,收工。

Update @ 2007-12-14

在和bxy讨论的过程中,又发现sed的另外一种用途,从html或xml中按照tag对应关系,筛选打印出指定的tag内容,使用了正则中的p命令,好像默认就没有“不能处理多行内容”以及“贪婪性”的问题,很好用,很强大:

    $ sed -n -e '/<title>/p' -e '/<text /,/<\/text>/p' from.xml

注意//不在同一行的时候才好用,不然会匹配到下一个实例出现的位置作为结束边界。

Related posts

Categories: Linux Tags: ,

在Ubuntu上加装Trac

August 8th, 2007 Fwolf 2 comments

原本机器上就架着svn服务器,但以前是从windows平台下转过来的,所以配套的轻型项目管理工具一直是在用Mantis,相比之下,trac和svn的结合程度更高一些,所以装一个试用一下。

相关软件版本:Ubuntu 7.04, Apache 2.2.3, Python 2.5.1, Trac 0.10.4。

安装trac,创建仓库

安装trac

首先通过apt安装trac,由于trac需要python的一些包,所以根据本机python环境的不同,可能还需要安装一些附加的包,我的机器上是自动安装了如下软件包:

python-clearsilver python-setuptools python-subversion trac

默认的,trac的程序文件是安装在/usr/share/trac目录下,包括很多默认的样式、模板也都在这个目录下。

创建env目录

trac需要创建env目录,用于存储trac生成的页面、配置文件等,也就是存储“内容”的地方,把程序和程序生成的数据文件分开是个好习惯。在trac中,这个目录被称为environment

A Trac environment is the backend storage where Trac stores information like wiki pages,
tickets, reports, settings, etc. An environment is basically a directory that contains a    
human-readable configuration file and various other files and directories.

我创建的是/big2/trac/svntest的目录,对应svn里面的svntest仓库:

$ trac-admin /big2/trac/svntest initenv
Creating a new Trac environment at /big2/trac/svntest

Trac will first ask a few questions about your environment 
in order to initalize and prepare the project database.

 Please enter the name of your project.
 This name will be used in page titles and descriptions.

Project Name [My Project]> SvnTest

 Please specify the connection string for the database to use.
 By default, a local SQLite database is created in the environment 
 directory. It is also possible to use an already existing 
 PostgreSQL database (check the Trac documentation for the exact 
 connection string syntax).

Database connection string [sqlite:db/trac.db]> 

 Please specify the type of version control system,
 By default, it will be svn.

 If you don't want to use Trac with version control integration, 
 choose the default here and don't specify a repository directory. 
 in the next question.

Repository type [svn]> 

 Please specify the absolute path to the version control 
 repository, or leave it blank to use Trac without a repository.
 You can also set the repository location later.

Path to repository [/path/to/repos]> https://somewhere.fwolf.com/svn/svntest

 Please enter location of Trac page templates.
 Default is the location of the site-wide templates installed with Trac.

Templates directory [/usr/share/trac/templates]> 

Creating and Initializing Project
 Installing default wiki pages
 /usr/share/trac/wiki-default/RecentChanges => RecentChanges
 /usr/share/trac/wiki-default/CamelCase => CamelCase
 /usr/share/trac/wiki-default/InterMapTxt => InterMapTxt
 /usr/share/trac/wiki-default/InterTrac => InterTrac
 /usr/share/trac/wiki-default/InterWiki => InterWiki
 /usr/share/trac/wiki-default/TitleIndex => TitleIndex
 /usr/share/trac/wiki-default/SandBox => SandBox
 /usr/share/trac/wiki-default/TracInterfaceCustomization => TracInterfaceCustomization
 /usr/share/trac/wiki-default/TracAccessibility => TracAccessibility
 /usr/share/trac/wiki-default/TracAdmin => TracAdmin
 /usr/share/trac/wiki-default/TracBackup => TracBackup
 /usr/share/trac/wiki-default/TracBrowser => TracBrowser
 /usr/share/trac/wiki-default/TracCgi => TracCgi
 /usr/share/trac/wiki-default/TracChangeset => TracChangeset
 /usr/share/trac/wiki-default/TracEnvironment => TracEnvironment
 /usr/share/trac/wiki-default/TracFastCgi => TracFastCgi
 /usr/share/trac/wiki-default/TracGuide => TracGuide
 /usr/share/trac/wiki-default/TracImport => TracImport
 /usr/share/trac/wiki-default/TracIni => TracIni
 /usr/share/trac/wiki-default/TracInstall => TracInstall
 /usr/share/trac/wiki-default/TracModPython => TracModPython
 /usr/share/trac/wiki-default/TracLinks => TracLinks
 /usr/share/trac/wiki-default/TracLogging => TracLogging
 /usr/share/trac/wiki-default/TracTicketsCustomFields => TracTicketsCustomFields
 /usr/share/trac/wiki-default/TracNotification => TracNotification
 /usr/share/trac/wiki-default/TracPermissions => TracPermissions
 /usr/share/trac/wiki-default/TracPlugins => TracPlugins
 /usr/share/trac/wiki-default/TracQuery => TracQuery
 /usr/share/trac/wiki-default/TracReports => TracReports
 /usr/share/trac/wiki-default/TracRevisionLog => TracRevisionLog
 /usr/share/trac/wiki-default/TracRoadmap => TracRoadmap
 /usr/share/trac/wiki-default/TracRss => TracRss
 /usr/share/trac/wiki-default/TracSearch => TracSearch
 /usr/share/trac/wiki-default/TracStandalone => TracStandalone
 /usr/share/trac/wiki-default/TracSupport => TracSupport
 /usr/share/trac/wiki-default/TracSyntaxColoring => TracSyntaxColoring
 /usr/share/trac/wiki-default/TracTickets => TracTickets
 /usr/share/trac/wiki-default/WikiRestructuredText => WikiRestructuredText
 /usr/share/trac/wiki-default/TracTimeline => TracTimeline
 /usr/share/trac/wiki-default/TracUnicode => TracUnicode
 /usr/share/trac/wiki-default/TracUpgrade => TracUpgrade
 /usr/share/trac/wiki-default/TracWiki => TracWiki
 /usr/share/trac/wiki-default/WikiDeletePage => WikiDeletePage
 /usr/share/trac/wiki-default/WikiFormatting => WikiFormatting
 /usr/share/trac/wiki-default/WikiHtml => WikiHtml
 /usr/share/trac/wiki-default/WikiMacros => WikiMacros
 /usr/share/trac/wiki-default/WikiNewPage => WikiNewPage
 /usr/share/trac/wiki-default/WikiPageNames => WikiPageNames
 /usr/share/trac/wiki-default/WikiProcessors => WikiProcessors
 /usr/share/trac/wiki-default/WikiRestructuredTextLinks => WikiRestructuredTextLinks
 /usr/share/trac/wiki-default/WikiStart => WikiStart

Warning:

You should install the SVN bindings

---------------------------------------------------------------------
Project environment for 'SvnTest' created.

You may now configure the environment by editing the file:

  /big2/trac/svntest/conf/trac.ini

If you'd like to take this new project environment for a test drive,
try running the Trac standalone web server `tracd`:

  tracd --port 8000 /big2/trac/svntest

Then point your browser to http://localhost:8000/svntest.
There you can also browse the documentation for your installed
version of Trac, including information on further setup (such as
deploying Trac to a real web server).

The latest documentation can also always be found on the project
website:

http://trac.edgewall.org/

Congratulations!

提示信息比较多,真正需要用户输入的就那么几项:

  • Project Name [My Project]> SvnTest 项目名称,帮助辨识而已。
  • Database connection string [sqlite:db/trac.db]> 数据库的连接串,使用的默认值(直接回车即可)。
  • Repository type [svn]> 仓库类型,使用默认值(svn),trac也可以连cvs等其他类型的仓库么?
  • Path to repository [/path/to/repos]> https://somewhere.fwolf.com/svn/svntest 仓库地址,风轻扬说只能连本机的仓库地址,可我输入的http仓库地址好像也能用。的确是只能用本机的路径,http形式的仓库地址会提示错误:

    TracError: https:/office.fwolf.com/svn/svntest does not appear to be a Subversion repository.
    

    直接修改配置文件/big2/trac/svntest/conf/trac.ini就可以了,里面的[trac]段,repository_dir设置为本机的svn仓库文件地址,比如/big2/svn/svntest,不用重启服务就生效了。

  • Templates directory [/usr/share/trac/templates]> 模板地址,用默认。

简单运行

至此,trac已经可以运行和访问了,不过类似本机的svn服务器,首先需要手工开启服务:

$ tracd --port 8000 /big2/trac/svntest

然后就能用地址http://localhost:8000/svntest访问了,如果错输为http://localhost:8000/,它还会提示用户当前有哪些项目可用(Available Projects)并给出链接地址。

把trac配置到apache上

每次都要手工启用trac服务肯定是麻烦的,所以还是像svn那样配置到apache上用着才方便,有几种方式可选:cgi方式和mod_python方式,另外还有fastcgi方式,不过fastcgi我不熟悉,就不介绍了,相关资料可以参考官方文档Trac with FastCGI

CGI方式

cgi程序设定

虽然cgi方式比其他方法要慢一些,还是介绍一下。首先就是在apache中配置cgi的执行程序,这里我采用比较简单的ScriptAlias方式,也可以吧trac.cgi复制到apache的cgi-bin目录下,或者ln过去(不过cgi-bin目录要开放FollowSymLinks选项才行:

ScriptAlias /trac /usr/share/trac/cgi-bin/trac.cgi

光能执行cgi程序还不够,trac还主要知道一些环境变量才能工作,主要是environment目录的位置,不然会提示错误:

EnvironmentError: The environment options "TRAC_ENV" or "TRAC_ENV_PARENT_DIR" or the mod_python options "TracEnv" or "TracEnvParentDir" are missing. Trac requires one of these options to locate the Trac environment(s).

根据trac用法的不同,这个环境变量的设置有两种方式,一种是trac只用于一个项目,那么只需要定义一个TRAC_ENV,指定env目录的地址即可;另外一种情况是trac用于多个项目,通常所有的env目录都是在同一个目录之下,所以定义TRAC_ENV_PARENT_DIR,指定env目录的上级目录:

<Location "/trac">
    # Select one of below Env according your usage of trac
    # Trac is for single environment
    #SetEnv TRAC_ENV "/big2/trac/svntest"
    # Trac is for multi environment
    SetEnv TRAC_ENV_PARENT_DIR "/big2/trac"
</Location>

这里我采用的是多env方式。

运行于apache下是env目录的权限(mod_python方式也适用,不再累述)

注意在cgi或者mod_python方式下,env目录的owner需要设置为web服务器的用户,在ubuntu上一般是www-data,不然会没有访问权限:

svntest: Error
(The user www-data requires read _and_ write permission to the database file /big2/trac/svntest/db/trac.db and the directory it is located in.)

mod_python方式

安装python支持

mod_python方式不仅比cgi方式速度更快,而且可以借助apache的强大功能实现一些tracd(简单运行方式)无法实现的功能,也是我个人比较喜欢的方式。python基本上是所有linux平台下的必备软件,接下来就是要安装apache的python模块libapache2-mod-python,然后在apache的conf文件中装载python模块,在ubuntu或者debian中则有更方便的做法:

a2enmod mod_python

想测试python是否正常支持的话,可以配一个Location测试一下:

<Location /mpinfo>
    SetHandler mod_python
    PythonInterpreter main_interpreter
    PythonHandler mod_python.testhandler
</Location>

虽然不懂python,但只要能出现正常的信息页(类似phpinfo页)就说明python安装正常了。

配置env目录

和cgi方式类似,也分单项目和多项目的形式,并且多项目也是用环境变量TracEnvParentDir来实现的,注意这个TracEnvParentDir是python的设置(option),和cgi的环境变量TRAC_ENV_PARENT_DIR名称不同。单env目录的的配置如下:

<Location /trac/svntest>
    SetHandler mod_python
    PythonInterpreter main_interpreter
    PythonHandler trac.web.modpython_frontend
    PythonOption TracEnv /big2/trac/svntest
    PythonOption TracUriRoot /trac/svntest
</Location>

文档中说TracUriRoot在某些情况下不是必需的,除非你看到如下错误信息:

404 Not Found (No handler matched request to %s)

多env目录的配置如下,使用了TracEnvParentDir:

<Location /trac>
    SetHandler mod_python
    PythonInterpreter main_interpreter
    PythonHandler trac.web.modpython_frontend
    PythonOption TracEnvParentDir /big2/trac
    PythonOption TracUriRoot /trac
</Location>

这样配置,如果访问http://domain.com/trac,会列出现有env目录列表,如果想禁止这个列表,可以用LocationMatch替代Location:

<LocationMatch "/trac/.+">

这样env列表页就无法显示了。

其他

静态文件映射出来让apache处理

静态文件脱离cgi或python的处理,由apache直接负责会对速度有一些提升,用apache的别名把他们直接指向到实际文件路径就可以了,由于执行的顺序问题,需要注意Alias必须放在ScriptAlias的前面,就像这样:

Alias /trac/svntest/chrome/common /usr/share/trac/htdocs
ScriptAlias /trac /usr/share/trac/cgi-bin/trac.cgi

看一看页面引用的css地址:/trac/svntest/chrome/common/css/trac.css,可以看到图像的地址在Alias的处理范围之内(注意本例Alias地址中包含了仓库名称)。如果有多个env目录,逐一创建Alias很麻烦,可以在每个env目录的trac.ini文件[trac]段htdocs_location中设定一个公用的资源文件地址,比如:

[trac]
htdocs_location = /trac-htdocs

这样在apache中也只需要设定一个Alias就可以了:

Alias /trac-htdocs /usr/share/trac/htdocs

这样我们的css地址就变成了/trac-htdocs/css/trac.css。不过logo图像和icon图片的地址好像不受htdocs_location控制,转换不过来。

身份验证

trac的身份验证仍然是通过apache的机制,比如我们常用的、最简单的mod_auth_basic,比如一下配置:

<LocationMatch "/trac/[^/]+/login">
    AuthType Basic
    AuthName "Fwolf's Trac"
    AuthUserFile /big2/svn/svnpasswd
    Require valid-user
</LocationMatch>

在这里我直接使用了svn的passwd文件,用户就不用记多个密码了。这样设置只是在用户登录的时候验证身份,如果想让用户一进入trac就需要验证身份,把LocationMatch改成这样就行了:

<LocationMatch "/trac/.+">

不过logout好像就不能用了。另外这样配置trac的用户登录信息是存储在浏览器中的,在需要的时候会自动被调用,所以logout以后,如果不关闭浏览器就重新login,不用再输入密码就直接验证成功了。

如果想定制某些用户能访问某些env,trac好像没有这方面的权限控制功能(wiki的开放性贯彻的真彻底,不过在某些场合下确实需要),依然可以通过apache来实现:

<LocationMatch "/trac/(svntest|other_env)">
    ...
    require user user1 user2

trac只是能够使用通过apache验证的用户名罢了。

关于中文的一些问题

如果源码或上传文件内容乱码,可以看看conf/trac.ini里[trac]段选项default_charset,如果你svn仓库里的文件和上传文件编码类型都是utf-8的话,把这个设置为utf-8即可。

参考:

Related posts

Categories: Linux, Svn/Git Tags: