Windows下架设Subversion服务器

7:25:00 PM 0 Comments

作者:indian

版本:v1.2

修订:2008年1月24日11:45:35

出处:http://indian.blog.163.com/blog/static/10881582007112415021751

版权:作者保留对本文的一切修改、发布等权力。任何人想要转载本文部分或全部内容时,必须保留包括作者、版本、修订、出处、版权,共五项信息。对本文的参考引用,则不受限制。

 

关键词:subversion, 安装配置, 权限, 目录访问

 

1 前言
2 基本概念
 2.1 什么是版本控制
 2.2 什么是 Subversion
 2.3 版本库(repository)
3 安装配置
 3.1 安装独立服务器 SVNServer
 3.2 安装 ApacheSVN 服务器
4 FAQ
5 参考资料

 

 

1、前 言

 

花了72小时,终于把 Subversion 初步掌握了。从一个连"什么是版本控制"都不知道的门外汉,到配置出精确至每目录访问的入门者,中间还卡了一天时间。其中费了许多气力,摸索实验了多次, 还差点放弃了,但是收获是巨大的。现把我的配置和学习过程写下来,供大家参考,也让初学者少走弯路。

以下仅以 Windows 平台为例讲解,Unix/Linux 平台请参考相关资料。如其中有谬误的地方,包括错别字,请联系我修订。

技术在分享中进步!

 

 

2、基本概念

 

2.1、什么是版本控制

简单点来说,版本控制就是数据仓库,它可以记录你对文件的每次更改。这样,就算你在昏天黑地的改了几个月后老板说不要了,还是按照过去那样,你也不会抓狂,简单的恢复版本操作就搞定一切。

 

2.2、什么是 Subversion

Subversion是一个自由/开源版本控制系统,它管理文件和目录可以超越时间。一组文 件存放在中心版本库,这个版本库很像一个普通的文件服务器,只是它可以记录每一次文件和目录的修改,这便使你可以取得数据以前的版本,从而可以检查所作的 更改。从这个方面看,许多人把版本控制系统当作一种"时间机器"。

Subversion可以通过网络访问它的版本库,从而使用户可以在不同的电脑上使用。一定 程度上可以说,允许用户在各自的地方修改同一份数据是促进协作。进展可能非常的迅速,并没有一个所有的改变都会取得效果的通道,由于所有的工作都有历史版 本,你不必担心由于失去某个通道而影响质量,如果存在不正确的改变,只要取消改变。

一些版本控制系统也是软件配置管理(SCM)系统,这种系统经过特定的精巧设计来管理源代 码,有许多关于软件开发的特性—本身理解编程语言、或者提供构建程序的工具。然而,Subversion不是这样一个系统,它是一个通用系统,可以管理任 何类型的文件集,对你这可能是源代码,对别人,可能是一个货物报价单或者是书稿等。

 

2.3、版本库(repository)

Subversion 的核心就是 repository ,中文翻译成"版本库"。就是位于服务器端,统一管理和储存数据的地方。

 

 

3、安装配置

 

3.1 安装独立服务器 SVNServer

环境

OS:Windows XP SP2

Web:Apache 2.2.6

SVN:svn-win32-1.4.6

 

一、准备工作

1、获取 Subversion 服务器程序

到官方网站(http://subversion.tigris.org/)下载最新的服务器安装程序。目前最新的是1.4.6版本,具体下载地址在:http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=8100&expandFolder=8100&folderID=91 ,注意找 for apache 2.2.x 版本的。

2、获取 TortoiseSVN 客户端程序

从官方网站 http://tortoisesvn.net/downloads 获取最新的 TortoiseSVN 。TortoiseSVN 是一个客户端程序,用来与 subvers 服务器端通讯。Subversion 自带一个客户端程序 svn.exe ,但 TortoiseSVN 更好操作,提高效率。

 

二、安装服务器端和客户端

首先安装 Apache 2.2.6 ,具体安装方法大家参考相关资料,或者参看我写的《Windows下安装Apache 2.2.x》。

其次安装 Subversion(以下简称SVN)的服务器端和客户端。下载下来的服务器端是个 zip 压缩包,直接解压缩即可,比如我解压到 E:\subversion 。客户端安装文件是个 exe 可执行文件,直接运行按提示安装即可,客户端安装完成后提示重启。

 

三、建立版本库(Repository)

运行Subversion服务器需要首先要建立一个版本库(Repository)。版本库可以看作是服务器上集中存放和管理数据的地方。

开始建立版本库。首先建立 e:\svn 空文件夹作为所有版本库的根目录。然后,进入命令行并切换到subversion的bin目录。输入如下命令:

svnadmin create E:\svn\repos1

此命令在 E:\svn 下建立一个版本库 repos1 。repos1 下面会自动生成一些文件夹和文件。

我们也可以使用 TortoiseSVN 图形化的完成这一步:

先建立空目录 E:\svn\repos1 ,注意一定是要空的。然后在 repos1 文件夹上"右键->TortoiseSVN->Create Repository here...",然后可以选择版本库模式,这里使用默认的FSFS即可,然后就创建了一系列文件夹和文件,同命令行建立的一样。

 

四、运行独立服务器

此时 subversion 服务还没有开始,只是通过它的命令建立了版本库。继续在刚才的命令窗口输入:

svnserve.exe --daemon

svnserve 将会在端口 3690 等待请求,--daemon(两个短横线)选项告诉 svnserve 以守护进程方式运行,这样在手动终止之前不会退出。注意不要关闭命令行窗口,关闭窗口会把 svnserve 停止。

为了验证svnserve正常工作,使用TortoiseSVN -> Repo-browser 来查看版本库。在弹出的 URL 对话框中输入:

svn://localhost/svn/repos1

点 OK 按钮后就可以看见 repos1 版本库的目录树结构了,只不过这时 repos1 是个空库。

你也可以使用--root选项设置根位置来限制服务器的访问目录,从而增加安全性和节约输入svnserve URL的时间:

svnserve.exe --daemon --root drive:\path\to\repository

以前面的测试作为例,svnserve 将会运行为:

svnserve.exe --daemon --root e:\svn

然后TortoiseSVN中的版本库浏览器URL缩减为:

svn://localhost/repos1

 

五、配置用户和权限

用文本编辑器打开E:\svn\repos1\conf目录,修改svnserve.conf:

将:

# password-db = passwd

改为:

password-db = passwd

即去掉前面的 # 注释符,注意前面不能有空格。

然后修改同目录的passwd文件,增加一个帐号:

将:

[users]
# harry = harryssecret
# sally = sallyssecret

增加帐号:

[users]
#harry = harryssecret
#sally = sallyssecret
test = test

 

六、初始化导入

下面就是将我们的数据(项目)导入到这个版本库,以后就由版本库管理我们的数据。我们的任何改动都回被版本库记录下来,甚至我们自己丢失、改错数据时版本库也能帮我们找回数据。

比如,我在 d:\wwwroot 下有个 guestbook 文件夹,里面存放的是我编写的留言簿程序。在此文件夹上"右键 -> TortoiseSVN -> Import..." ,在弹出对话框的"URL of repository"输入"svn://localhost/repos1/guestbook"。在"Import message"输入"导入整个留言簿"作为注释。
点 OK 后要求输入帐号。我们在用户名和密码处都输入 test 。完成后 guestbook 中的内容全部导入到了 svn://localhost/svn/repos1/guestbook 。

我们看到在 e:\svn\repos1 没有任何变化,连个 guestbook 文件夹都没有建立,唯一的变化就是e:\svn\repos1容量变大了。实际上我们源guestbook中的内容已经导入 repos1 版本库了,源 guestbook 文件夹可以删除了。

需要注意的是,这一步操作可以完全在另一台安装了 TortoiseSVN 的客户机上进行。例如运行svnserve的主机的IP是133.96.121.22,则URL部分输入的内容就是"svn://133.96.121.22" 。

 

七、基本操作流程

1、取出(check out)

取出版本库到一个工作拷贝:

来到任意空目录下,比如在f分区建立一个空文件夹 f:\work 。"右键 -> SVN Checkout"。在"URL of repository"中输入"svn://localhost/svn/repos1/guestbook",这样我们就得到了一份 guestbook 中内容的工作拷贝。

2、存入(check in)/提交(commit)

在工作拷贝中作出修改并提交:

在 guestbook 工作拷贝中随便打开一个文件,作出修改,然后"右键 -> SVN Commit... "。这样我们就把修改提交到了版本库,版本库根据情况存储我们提交的数据。

在修改过的文件上"右键 -> TortoiseSVN -> Show Log" ,可以看到对这个文件所有的提交。在不同的 revision 条目上"右键 -> Compare with working copy",我们可以比较工作拷贝的文件和所选 revision 版本的区别。

 

 

3.2 安装 ApacheSVN 服务器

Subversion的设计包括一个抽象的网络层,这意味着版本库可以通过各种服务器进程访问。理论上讲,Subversion可以使用无限数量的网络协议实现,目前实践中存在着两种服务器。

 

  • SVNServer:svnserve 是一个小的(也叫轻型的)、独立服务器,使用自己定义的协议和客户端。(作者注:以下称这种服务器为"svnserver服务器",上面的安装配置就是安装svnserver服务器。)


  • ApacheSVN:Apache是最流行的web服务器,通过使用 mod_dav_svn 模块,Apache可以访问版本库,并且可以使客户端使用HTTP的扩展协议WebDAV/DeltaV进行访问。(作者注:以下称这种服务器为"ApacheSVN服务器")

 

通过 Http 协议访问版本库是 Subversion 的亮点之一。ApacheSVN服务器 具备了许多 svnserve服务器 没有的特性,使用上更加灵活,但是有一点难于配置,灵活通常会带来复杂性。

由于 Subversion 需要版本化的控制,因此标准的 Http 协议不能满足需求。要让 Apache 与 Subversion 协同工作,需要使用 WebDAV(Web-based Distributed Authoring and Versioning:)Web 分布式创作和版本控制)。WebDAV 是 HTTP 1.1 的扩展,关于 WebDAV 的规范和工作原理,可以参考 IETF RFC 2518

 

一、必备条件

为了让你的版本库使用HTTP网络,你必需具备以下几个条件:

  1. 配置好httpd 2.2.x,并且使用mod_dav启动。
  2. 为mod_dav安装mod_dav_svn插件。
  3. 配置你的httpd.conf,使http协议能访问版本库。

下面以我的配置过程详细讲解。

环境:

OS:Windows XP SP2

Web:Apache 2.2.6

SVN:svn-win32-1.4.6

 

二、安装

1、安装Apache

具体安装方法见:《Windows下安装Apache 2.2.x

2、安装 Subversion

将下载下来的 svn-win32-1.4.6.zip 直接解压即可,比如我解压到 e:\subversion 。
从Subversion安装目录的 bin 子目录将 intl3_svn.dll、libdb44.dll、mod_authz_svn.so、mod_dav_svn.so 拷贝到Apache的模块目录(Apache 安装目录的 modules 文件夹)。

 

三、基本的Apache配置

修改Apache的配置文件 httpd.conf ,使用LoadModule来加载mod_dav_svn模块。

将:

#LoadModule dav_module modules/mod_dav.so

改成:

LoadModule dav_module modules/mod_dav.so

即去掉前面的"#"号。

添加:

LoadModule dav_svn_module modules/mod_dav_svn.so

一定确定它在 mod_dav 之后。

现在你已经设置了Apache和Subversion,但是Apache不知道如何处理 Subversion客户端,例如TortoiseSVN。为了让Apache知道哪个目录是用来作为Subversion版本库,你需要使用编辑器(例 如记事本)编辑Apache的配置文件。

在配置文件最后添加如下几行:

<Location /repository/>
  DAV svn
  SVNPath e:/svn/repos1
</Location>

这个配置告诉Apache首先需要启用 dav_module,然后加载 dav_svn_module 。版本库对外的URL是:http://服务器IP/repository/ ,所有的Subversion版本库在物理上位于e:/svn/repos1/ 。

配置完毕后重新启动 Apache,打开浏览器,输入 http://服务器IP/ repository/ 将会看到如下画面:

这表示 Apache 的 dav_svn 模块已经可以正常工作了。用户可以使用任何一种 Subversion 的客户端通过 Http 协议访问你的版本库。

如果想要指定多个版本库,可以用多个 Location 标签,也可以使用 SVNParentPath 代替 SVNPath,例如在 e:\svn 下有多个版本库 repos1,repos2 等等,用如下方式指定:

<Location /repository/>
 DAV svn
 SVNParentPath e:/svn
</Location>

"SVNParentPath e:/svn " 表示 e:\svn 下的每个子目录都是一个版本库。可以通过 http://服务器IP/repository/repos1/http://服务器IP/repository/repos2/ 来访问。

现在你的版本库任何人都可以访问,并且有完全的写操作权限。也就是说任何人都可以匿名读取, 修改,提交,以及删除版本库中的内容(注:这时不需要配置E:\svn\repos\conf\svnserve.conf 文件,并且也不需要启动E:\subversion\bin\svnserve.exe。因为提交是通过Apache的dav模块处理的,而不是由 svnservice处理。)。我们用 TortoiseSVN 客户端验证即知。

显然大部分场合这是不符合需求的。那么如何进行权限设置呢,Apache 提供了基本的权限设置:

 

四、认证选项

1、基本 HTTP 认证

最简单的客户端认证方式是通过 HTTP 基本认证机制,简单的使用用户名和密码来验证一个用户的身份。Apache提供了一个 htpasswd 工具来管理一个用户文件,这个文件包含用户名和加密后的密码,这些就是你希望赋予 Subversion 特别权限的用户。htpasswd 可以在 Apache 的 bin 安装目录下找到。具体使用方法如下:

创建用户文件:
htpasswd -c E:\usr\Apache2.2\bin\passwd.conf username

添加新用户(-m 表示以 MD5 加密密码,可选项):
htpasswd [-m] E:\usr\Apache2.2\bin\passwd.conf Newusername

更改用户密码:
htpasswd [-m] E:\usr\Apache2.2\bin\passwd.conf username

删除用户(要用大写的 D ):
htpasswd –D E:\usr\Apache2.2\bin\passwd.conf username

接下来修改 httpd.conf,在 Location 标签中加入如下内容:

AuthType Basic
AuthName "svn repos"
AuthUserFile E:/usr/Apache2.2/bin/passwd.conf
Require valid-user

说明:

AuthType Basic:启用基本的验证,比如用户名/密码对。

AuthName "svn repos":当一个认证对话框弹出时,出现在认证对话框中的信息。(最好用英文,TortoiseSVN 不支持中文,安装语言包除外。)

AuthUserFile E:/usr/Apache2.2/bin/passwd:指定E:\usr\Apache2.2\bin\passwd为用户文件,用来验证用户的用户名及密码。

Require valid-user:限定用户只有输入正确的用户名及密码后才能访问这个路径

 

重新启动 Apache ,打开浏览器访问版本库。Apache 会提示你输入用户名和密码来认证登陆了,现在只有 passwd 文件中设定的用户才可以访问版本库。也可以配置只有特定用户可以访问,替换上述 "Require valid-user" 为 "Require user tony robert" 将只有用户文件中的 tony 和 robert 可以访问该版本库。

有的时候也许不需要这样严格的访问控制,例如大多数开源项目允许匿名的读取操作,而只有认证用户才允许写操作。为了实现更为细致的权限认证,可以使用 Limit 和 LimitExcept 标签。例如:

<LimitExcept GET PROPFIND OPTIONS REPORT>
  require valid-user
</LimitExcept>

以上配置将使匿名用户有读取权限,而限制只有 passwd 中配置的用户可以使用写操作。

如果这还不能满足你的要求,你希望精确的控制版本库目录访问,可以使用 Apache 的 mod_authz_svn 模块对每个目录进行认证操作。

 

 

2、用 mod_authz_svn 进行目录访问控制

首先需要让 Apache 将 mod_authz_svn 模块加载进来。在 Subversion 的安装目录中找到 mod_auth_svn 模块,将其拷贝到 Apache 安装目录的 modules 子目录下。修改 httpd.conf 文件,添加:

LoadModule authz_svn_module modules/mod_authz_svn.so

现在可以在 Location 标签中使用 authz 的功能了。一个基本的 authz 配置如下:

<Location /repository/>
  DAV svn
  SVNParentPath e:/svn

  # our access control policy
  AuthzSVNAccessFile E:/usr/Apache2.2/bin/accesspolicy.conf

  # try anonymous access first, resort to real
  # authentication if necessary.
  Satisfy Any
  Require valid-user

  # how to authenticate a user
  AuthType Basic
  AuthName "Subversion repository"
  AuthUserFile E:/usr/Apache2.2/bin/passwd.conf
</Location>

AuthzSVNAccessFile 指向的是 authz 的策略文件,详细的权限控制可以在这个策略文件中指定。访问文件 accesspolicy.conf 的语法与svnserve.conf和 Apache 的配置文件非常相似,以(#)开头的行会被忽略;在它的简单形式里,每一小节命名一个版本库和一个里面的路径;认证用户名是在每个小节中的选项名;每个选 项的值描述了用户访问版本库的级别:r(只读)或者rw(读写),如果用户没有提到或者值留空,访问是不允许的; * 表示所有用户,用它控制匿名用户的访问权限;@符号区分组和用户。如:

[groups]
committers = paulex, richard
developers = jimmy, michel, spark, sean

[/]
* = r
@committers = rw

[/branches/dev]
@developers = rw

[/tags]
tony = rw
[/private]
* =
@committers= r

使用 SVNParentPath 代替 SVNPath 来指定多个版本库的父目录时,其中所有的版本库都将按照这个策略文件配置。例如上例中 tony 将对所有版本库里的 /tags 目录具有读写权限。如果要对具体每个版本库配置,用如下的语法:

[groups]
project1_committers = paulex, richard
project2_committers = jimmy, michel, spark, tony, Robert

[repos1:/]
* = r
@ project1_committer = rw

[repos2:/]
* = r
@ project2_committer = rw

这样项目1的 project1_committer 组只能对 repos1 版本库下的文件具有写权限而不能修改版本库 repos2 ,同样项目2的 project2_commiter 组也不能修改 repos1 版本库的文件。

 

 

4、FAQ

1、路径或权限不足时将出现错误信息提示:

http://localhost (路径不对)
Error * PROPFIND request failed on '/' PROPFIND of '/': 200 OK (http://localhost)

http://localhost/svn (权限不足)
Error * PROPFIND request failed on '/svn' PROPFIND of '/svn': 403 Forbidden (http://localhost)

http://localhost/svn/repos (正常显示)

http://localhost/repos (权限不允许)
Error * PROPFIND request failed on '/repos' PROPFIND of '/repos': 405 Method Not Allowed (http://localhost)

 

 

2、不启动E:\subversion\bin\svnserve.exe ,但启动了ApacheSVN ,访问(tortoiseSVN –> Repo – browser)或提交(SVN Commit)情形如下:

现象:svn://localhost/svn/repos 不能访问或提交,提示:Error * Can't connect to host 'localhost': 由于目标机器积极拒绝,无法连接。 但 file:///e:/svn/repos 和 http://localhost/svn/repos 可以访问或提交。

原因:svn:// 是独立服务器 svnserver 自己的协议。file:/// 是本地访问,即服务器端和客户端在一个机器上。

 

 

 

 

参考资料:
Subversion 官方网站:Subversion 的官方网站,提供最权威的介绍和最新的下载。
Subversion 中文手册:Subversion 简体中文官方网站翻译的中文手册。
TortoiseSVN 中文文档:Subversion 简体中文官方网站翻译的 TortoiseSVN 中文文档。
我用SVN中文论坛:国内人气非常旺的 SVN 中文交流论坛。
用Apache和Subversion搭建安全的版本控制环境》:IBM 工程师写的基于 Linux 的 SVN 教程。
百度百科:由全体网民共同撰写的百科全书

 

 

~ 全文完~

命令行笔记

5:03:00 PM 0 Comments

将文本按行倒序
tac urfile
sed '1!G;h;$!d' urfile

awk计算行值
awk '{print $1+$2}' urfile

awk计算列值
awk 'BEGIN{total=0}{total+=$1}END{print total}' urfile

perl计算行值
perl -ane '{$total=@F[0]+@F[1];print $total;print "\n"}' urfile

perl计算列值
perl -ane '{$total+=@F[0];}END{print $total;print "\n"}' urfile

删除包含aaa但不包含bbb的行
sed '/aaa/{/bbb/!d}' urfile

文件列转行
设urfile文件有如下文本
aaa
bbb
ccc
ddd
现要得到
aaa bbb ccc ddd
方法如下
xargs < urfile
awk '{printf "%s ", $0}END{print ""}' urfile
paste -sd' ' urfile
echo `cat urfile`
perl -00 -pe 's{\n}{ }gs' urfile
sed '{:1;N;s/\n/ /g;b 1}' urfile

文本行列倒置
#!/bin/sh
#ScriptName:rotate

[ $# -ne 1 ] && exit 1
if [ ! -s $1 ]
then
    echo "Usage:rotate datafile"
    exit 1
fi
row=`sed -n '$=' $1`
col=`awk 'NR==1{print NF}' $1`
awk -v row=$row -v col=$col '{for(i=1;i<=NF;i++)a[NR"-"i]=$i} END{ for(i=1;i<=col;i++){ for(j=1;j<=row;j++) printf("%s ",a[j"-"i]);printf("\n") } }' $1

文件名取值

#FILE=/dir1/dir2/dir3/my.file.txt

#echo $FILE
/dir1/dir2/dir3/my.file.txt

#echo ${FILE#*/}
dir1/dir2/dir3/my.file.txt

#echo ${FILE##*/}
my.file.txt

#echo ${FILE#*.}
file.txt

#echo ${FILE##*.}
txt

#echo ${FILE/*}
/dir1/dir2/dir3

#echo ${FILE%%/*}

#echo ${FILE%.*}
/dir1/dir2/dir3/my.file

#echo ${FILE%%.*}
/dir1/dir2/dir3/my

删除第二次匹配create到末尾的行
sed '0,/create/b;//Q' urfile

合并两个文件
(sort -m file1;sort -m file2) > file3

查看程序用到哪些库
ldd program

静态库操作
ar rc libmy.a 创建一个库
ar rs libmy.a 1.o 向库添加模块
ar t libmy.a 查看库中模块
at d libmy.a 1.o 删除库中模块

查看端口25
lsof -i:25

文件格式转换
sed -e 's/$/\r/' myunix.txt > mydos.txt
sed -e 's/.$//' mydos.txt > myunix.txt

查看出现至少两次的行
grep '4\{2,\}' urfile
grep '8\{2,6\}3' urfile

查找可用源
apt-spy -d testing -a Asia -o sources.out

make 预定义变量
$@
  表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。

$%
  仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a(bar.o)",那么,"$%"就是 "bar.o","$@"就是"foo.a"。如果目标不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。

$<
  依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。

$?
  所有比目标新的依赖目标的集合。以空格分隔。

$^
  所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。

$+
  这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。

$*
  这个变量表示目标模式中"%"及其之前的部分。如果目标是"dir/a.foo.b",并且目标的模式是"a.%.b",那么,"$*"的值就是"dir /a.foo"。这个变量对于构造有关联的文件名是比较有较。如果目标中没有模式的定义,那么"$*"也就不能被推导出,但是,如果目标文件的后缀是 make所识别的,那么"$*"就是除了后缀的那一部分。例如:如果目标是"foo.c",因为".c"是make所能识别的后缀名,所以," $*"的值就是"foo"。这个特性是GNU make的,很有可能不兼容于其它版本的make,所以,你应该尽量避免使用"$*",除非是在隐含规则或是静态模式中。如果目标中的后缀是make所不 能识别的,那么"$*"就是空值。

当你希望只对更新过的依赖文件进行操作时,"$?"在显式规则中很有用,例如,假设有一个函数库文件叫"lib",其由其它几个object文件更新。那么把object文件打包的比较有效率的Makefile规则是:

  lib : foo.o bar.o lose.o win.o
        ar r lib $?

在 上述所列出来的自动量变量中。四个变量($@、$<、$%、$*)在扩展时只会有一个文件,而另三个的值是一个文件列表。这七个自动化变量还可以取 得文件的目录名或是在当前目录下的符合模式的文件名,只需要搭配上"D"或"F"字样。这是GNU make中老版本的特性,在新版本中,我们使用函数"dir"或"notdir"就可以做到了。"D"的含义就是Directory,就是目录,"F"的 含义就是File,就是文件。

下面是对于上面的七个变量分别加上"D"或是"F"的含义:

$(@D)
  表示"$@"的目录部分(不以斜杠作为结尾),如果"$@"值是"dir/foo.o",那么"$(@D)"就是"dir",而如果"$@"中没有包含斜杠的话,其值就是"."(当前目录)。

$(@F)
  表示"$@"的文件部分,如果"$@"值是"dir/foo.o",那么"$(@F)"就是"foo.o","$(@F)"相当于函数"$(notdir $@)"。

"$(*D)"
"$(*F)"
  和上面所述的同理,也是取文件的目录部分和文件部分。对于上面的那个例子,"$(*D)"返回"dir",而"$(*F)"返回"foo"

"$(%D)"
"$(%F)"
  分别表示了函数包文件成员的目录部分和文件部分。这对于形同"archive(member)"形式的目标中的"member"中包含了不同的目录很有用。

"$(<D)"
"$(<F)"
  分别表示依赖文件的目录部分和文件部分。

"$(^D)"
"$(^F)"
  分别表示所有依赖文件的目录部分和文件部分。(无相同的)

"$(+D)"
"$(+F)"
  分别表示所有依赖文件的目录部分和文件部分。(可以有相同的)

"$(?D)"
"$(?F)"
  分别表示被更新的依赖文件的目录部分和文件部分。

最后想提醒一下的是,对于"$<",为了避免产生不必要的麻烦,我们最好给$后面的那个特定字符都加上圆括号,比如,"$(<)"就要比"$<"要好一些。

还得要注意的是,这些变量只使用在规则的命令中,而且一般都是"显式规则"和"静态模式规则"(参见前面"书写规则"一章)。其在隐含规则中并没有意义

关于命令的变量。

AR
  函数库打包程序。默认命令是"ar"。
AS
  汇编语言编译程序。默认命令是"as"。
CC
  C语言编译程序。默认命令是"cc"。
CXX
  C++语言编译程序。默认命令是"g++"。
CO
  从 RCS文件中扩展文件程序。默认命令是"co"。
CPP
  C程序的预处理器(输出是标准输出设备)。默认命令是"$(CC) –E"。
FC
  Fortran 和 Ratfor 的编译器和预处理程序。默认命令是"f77"。
GET
  从SCCS文件中扩展文件的程序。默认命令是"get"。
LEX
  Lex方法分析器程序(针对于C或Ratfor)。默认命令是"lex"。
PC
  Pascal语言编译程序。默认命令是"pc"。
YACC
  Yacc文法分析器(针对于C程序)。默认命令是"yacc"。
YACCR
  Yacc文法分析器(针对于Ratfor程序)。默认命令是"yacc –r"。
MAKEINFO
  转换Texinfo源文件(.texi)到Info文件程序。默认命令是"makeinfo"。
TEX
  从TeX源文件创建TeX DVI文件的程序。默认命令是"tex"。
TEXI2DVI
  从Texinfo源文件创建军TeX DVI 文件的程序。默认命令是"texi2dvi"。
WEAVE
  转换Web到TeX的程序。默认命令是"weave"。
CWEAVE
  转换C Web 到 TeX的程序。默认命令是"cweave"。
TANGLE
  转换Web到Pascal语言的程序。默认命令是"tangle"。
CTANGLE
  转换C Web 到 C。默认命令是"ctangle"。
RM
  删除文件命令。默认命令是"rm –f"。

关于命令参数的变量

下面的这些变量都是相关上面的命令的参数。如果没有指明其默认值,那么其默认值都是空。

ARFLAGS
  函数库打包程序AR命令的参数。默认值是"rv"。
ASFLAGS
  汇编语言编译器参数。(当明显地调用".s"或".S"文件时)。
CFLAGS
  C语言编译器参数。
CXXFLAGS
  C++语言编译器参数。
COFLAGS
  RCS命令参数。
CPPFLAGS
  C预处理器参数。( C 和 Fortran 编译器也会用到)。
FFLAGS
  Fortran语言编译器参数。
GFLAGS
  SCCS "get"程序参数。
LDFLAGS
  链接器参数。(如:"ld")
LFLAGS
  Lex文法分析器参数。
PFLAGS
  Pascal语言编译器参数。
RFLAGS
  Ratfor 程序的Fortran 编译器参数。
YFLAGS
  Yacc文法分析器参数。

脚本特殊变量
$0   脚本名
$n   脚本的第n个参数
$*   这个程式的所有参数
$#   这个程式的参数个数
$@   这个程式的参数列表
$$   这个程式的PID
$!   执行上一个背景指令的PID
$?   执行上一个指令的返回值

ipcs
-m   shared memory segments
-q   message queues
-s   semaphore arrays
-a   all (this is the default)
...

常用debian命令
apt-get update 更新源列表
apt-get install pkg 安装软件包
apt-get install --reinstall pkg 重新安装软件包
apt-get install --download-only --reinstall pkg 下载软件包
apt-get build-dep pkg 安装依赖包
apt-get remove pkg 先移除软件包
apt-get remove --purge pkg 彻底移除软件包
apt-cache search pkg 查找软件包
apt-cache search pkg --names-only 查找软件包(仅名称)
apt-cache show pkg 显示包信息

dpkg -I pkg.deb 显示包信息
dpkg -i pkg.deb 安装包
dpkg -c pkg.dev 查看包内容
dpkg -L pkg 查看包(已安装)内容
dpkg -s pkg 查看包(已安装)信息
dpkg -S xxx 相看xxx所属软件包
dpkg -x pkg.deb cc 将包解到cc目录中
dpkg -P pkg 清除软件包
dpkg -r pkg 移除软件包

apt-file update 更新源列表
apt-file search xxx查找源中xxx所属软件包

转换编码gb18030 to utf-8
iconv -f gb18030 -t utf-8 -o zh_CN.po pkg.po

wget下载命令
-c 断点续传
-r 递归下载
-nd 不递归创建目录
-np 不搜索上一层目录
-k 脱机浏览时用此项
-L 递归时不进入其它主机
-p 下载网页所需的所有文件
-A 指定要下载文件样式列表
-i 后跟一个文件指明要下载的URL
如:
wget -t0 -c -nH -np -b -m localdir URL -o wget.log

cpio文件制作
find . | cpio -H newc -o > ../file

cpio文件解开
cat file| cpio -i

分区相关(设硬盘80G,独立分区,不针对所有人,看贴者勿效仿)
/ 1~2 G
/boot ~300M
/usr ~15G
/var ~10G
/swap ~2*memory
/home rest

makefile小模板
all : libmy.so
SRC : print.c
TGT : $(SRC:.c=.o)
$(SRC): print.h
  @touch $@
%.o : %.c
  cc -c $?
libmy.so : $(TGT)
  cc -s -shared -o $@ $(TGT)

fcitx配置
#! /bin/sh

XMODIFIERS=@im=fcitx
GTK_IM_MODULE=fcitx
export XMODIFIERS GTK_IM_MODULE

if [ -x "/usr/bin/fcitx" ]; then
    /usr/bin/fcitx &
fi

scim配置
#! /bin/sh

export XMODIFIERS="@im=SCIM"
export GTK_IM_MODULE="scim"
export XIM_PROGRAM="scim -d"
#export QT_IM_MODULE="scim"

# -- help --
# modify LANG=zh_CN.UTF-8 in /etc/environment

mkiso
mkisofs -o mini.iso -b isolinux.bin -c boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table tree-of-root

makefile辅记
设当前目录有文件help.en.html makefile
makefile内容如下
NAME = $(wildcard *.html)

BASENAME = $(basename $(wildcard *.html))

SUFFIXNAME = $(addsuffix .c, $(basename $(wildcard *.html)))

PRENAME = $(addprefix install/, $(wildcard *.html))

SUBNAME = $(subst .,,$(basename $(wildcard *.html)))

all :
    @echo $(NAME)
    @echo $(BASENAME)
    @echo $(SUFFIXNAME)
    @echo $(PRENAME)
    @echo $(SUBNAME)
make时结果如下
help.en.html
help.en
help.en.c
install/help.en.html
helpen

ldconfig
可以将路径添加到/etc/ld.so.conf
再执行ldconfig
或执行ldconfig pathdir

qemu-img
qemu-img create hd.img 3G

qemu
qemu -boot d -cdrom mini.iso -hda hd.img

dpkg-scanpackages
dpkg-scanpackages [-u] . /dev/null | gzip > Packages.gz

灭掉U盘灯
umount U盘挂载目录
eject /dev/sda

mkisofs
mkisofs -o mini.iso -r -J -no-emul-boot -boot-load-size 4 -boot-info-table -b isolinux/isolinux.bin -c isolinux/boot.cat ./mm

wget
wget -t0 -c -nH -np -b -m link-of-download-file

find文本
find . -type f|perl -e 'while(<>){s/\n//;if(-T){print $_."\n"}}'
find . -type f|perl -e 'while(<>){s/\n//;if(!-B){print $_."\n"}}'

将匹配的行与上一行合并为一行
N;/\npattern/{s/\n/ /;p;d};P;D;

rsync同步
同步src与dest目录
rsync -avz src dest
同步src与dest,并将dest中多余的文件删除
rsync -avz --delete src dest

awk输出中间的连续列(如2-4列)
awk 'BEGIN{i=2;ORS=""}{ while( i<=4 ) {print $i " " ;i++} print "\n";i=2}'

curl使用简介

12:38:00 PM 0 Comments

curl使用简介

Curl是一个很强大的http命令行工具,其功能十分强大。

1) 二话不说,先从这里开始吧!

$ curl http://www.yahoo.com

回车之后,www.yahoo.com 的html就稀里哗啦地显示在屏幕上了    ~

2) 嗯,要想把读过来页面存下来,是不是要这样呢?

$ curl http://www.yahoo.com > page.html

当然可以,但不用这么麻烦的!

用curl的内置option就好,存下http的结果,用这个option: -o

$ curl -o page.html http://www.yahoo.com

这样,你就可以看到屏幕上出现一个下载页面进度指示。等进展到100%,自然就 OK咯

3) 什么什么?!访问不到?肯定是你的proxy没有设定了。

使用curl的时候,用这个option可以指定http访问所使用的proxy服务器及其端口: -x

$ curl -x 123.45.67.89:1080 -o page.html http://www.yahoo.com

4) 访问有些网站的时候比较讨厌,他使用cookie来记录session信息。

像IE/NN这样的浏览器,当然可以轻易处理cookie信息,但我们的curl呢?.....

我们来学习这个option: -D <— 这个是把http的response里面的cookie信息存到一个特别的文件中去

$ curl -x 123.45.67.89:1080 -o page.html -D cookie0001.txt http://www.yahoo.com

这样,当页面被存到page.html的同时,cookie信息也被存到了cookie0001.txt里面了

5)那么,下一次访问的时候,如何继续使用上次留下的cookie信息呢?要知道,很多网站都是靠监视你的cookie信息,来判断你是不是不按规矩访问他们的网站的。

这次我们使用这个option来把上次的cookie信息追加到http request里面去: -b

$ curl -x 123.45.67.89:1080 -o page1.html -D cookie0002.txt -b cookie0001.txt http://www.yahoo.com

这样,我们就可以几乎模拟所有的IE操作,去访问网页了!

6)稍微等等    ~我好像忘记什么了    ~

对了!是浏览器信息  

有些讨厌的网站总要我们使用某些特定的浏览器去访问他们,有时候更过分的是,还要使用某些特定的版本     NND,哪里有时间为了它去找这些怪异的浏览器呢!?

好在curl给我们提供了一个有用的option,可以让我们随意指定自己这次访问所宣称的自己的浏览器信息: -A

$ curl -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" -x 123.45.67.89:1080 -o page.html -D cookie0001.txt http://www.yahoo.com

这样,服务器端接到访问的要求,会认为你是一个运行在Windows 2000上的 IE6.0,嘿嘿嘿,其实也许你用的是苹果机呢!

而"Mozilla/4.73 [en] (X11; U; Linux 2.2; 15 i686"则可以告诉对方你是一台 PC上跑着的Linux,用的是Netscape 4.73,呵呵呵

7)另外一个服务器端常用的限制方法,就是检查http访问的referer。比如你先访问首页,再访问里面所指定的下载页,这第二次访问的 referer地址就是第一次访问成功后的页面地址。这样,服务器端只要发现对下载页面某次访问的referer地址不是首页的地址,就可以断定那是个盗 连了    ~

讨厌讨厌 ~我就是要盗连    ~!!

幸好curl给我们提供了设定referer的option: -e

$ curl -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" -x 123.45.67.89:1080 -e "mail.yahoo.com" -o page.html -D cookie0001.txt http://www.yahoo.com

这样,就可以骗对方的服务器,你是从mail.yahoo.com点击某个链接过来的了,呵呵呵

8)写着写着发现漏掉什么重要的东西了!——- 利用curl 下载文件

刚才讲过了,下载页面到一个文件里,可以使用 -o ,下载文件也是一样。比如,

$ curl -o 1.jpg http://cgi2.tky.3web.ne.jp/~zzh/screen1.JPG
这里教大家一个新的option: -O 大写的O,这么用:
$ curl -O http://cgi2.tky.3web.ne.jp/~zzh/screen1.JPG
这样,就可以按照服务器上的文件名,自动存在本地了!

再来一个更好用的。

如果screen1.JPG以外还有screen2.JPG、screen3.JPG、....、screen10.JPG需要下载,难不成还要让我们写一个script来完成这些操作?

不干!

在curl里面,这么写就可以了:

$ curl -O http://cgi2.tky.3web.ne.jp/~zzh/screen[1-10].JPG

呵呵呵,厉害吧?! ~

9)再来,我们继续讲解下载!

$ curl -O http://cgi2.tky.3web.ne.jp/~{zzh,nick}/[001-201].JPG

这样产生的下载,就是

~zzh/001.JPG
~zzh/002.JPG
...
~zzh/201.JPG
~nick/001.JPG
~nick/002.JPG
...
~nick/201.JPG

够方便的了吧?哈哈哈

咦?高兴得太早了。

由于zzh/nick下的文件名都是001,002...,201,下载下来的文件重名,后面的把前面的文件都给覆盖掉了 ~

没关系,我们还有更狠的!

$ curl -o #2_#1.jpg http://cgi2.tky.3web.ne.jp/~{zzh,nick}/[001-201].JPG

—这是.....自定义文件名的下载? —对头,呵呵!

这样,自定义出来下载下来的文件名,就变成了这样:原来: ~zzh/001.JPG —-> 下载后: 001-zzh.JPG 原来: ~nick/001.JPG —-> 下载后: 001-nick.JPG

这样一来,就不怕文件重名啦,呵呵

9)继续讲下载

我们平时在windows平台上,flashget这样的工具可以帮我们分块并行下载,还可以断线续传。curl在这些方面也不输给谁,嘿嘿

比如我们下载screen1.JPG中,突然掉线了,我们就可以这样开始续传

$ curl -c -O http://cgi2.tky.3wb.ne.jp/~zzh/screen1.JPG

当然,你不要拿个flashget下载了一半的文件来糊弄我    别的下载软件的半截文件可不一定能用哦 ~

分块下载,我们使用这个option就可以了: -r

举例说明

比如我们有一个http://cgi2.tky.3web.ne.jp/~zzh/zhao1.mp3 要下载(赵老师的电话朗诵 :D )我们就可以用这样的命令:

$ curl -r 0-10240 -o "zhao.part1" http:/cgi2.tky.3web.ne.jp/~zzh/zhao1.mp3 &\
$ curl -r 10241-20480 -o "zhao.part1" http:/cgi2.tky.3web.ne.jp/~zzh/zhao1.mp3 &\
$ curl -r 20481-40960 -o "zhao.part1" http:/cgi2.tky.3web.ne.jp/~zzh/zhao1.mp3 &\
$ curl -r 40961- -o "zhao.part1" http:/cgi2.tky.3web.ne.jp/~zzh/zhao1.mp3

这样就可以分块下载啦。不过你需要自己把这些破碎的文件合并起来如果你用UNIX或苹果,用 cat zhao.part* > zhao.mp3就可以如果用的是Windows,用copy /b 来解决吧,呵呵

上面讲的都是http协议的下载,其实ftp也一样可以用。用法嘛,

$ curl -u name:passwd ftp://ip:port/path/file

或者大家熟悉的

$ curl ftp://name:passwd@ip:port/path/file

10) 说完了下载,接下来自然该讲上传咯上传的option是 -T

比如我们向ftp传一个文件:

$ curl -T localfile -u name:passwd ftp://upload_site:port/path/

当然,向http服务器上传文件也可以比如

$ curl -T localfile http://cgi2.tky.3web.ne.jp/~zzh/abc.cgi

注意,这时候,使用的协议是HTTP的PUT method

刚才说到PUT,嘿嘿,自然让老服想起来了其他几种methos还没讲呢! GET和POST都不能忘哦。

http提交一个表单,比较常用的是POST模式和GET模式

GET模式什么option都不用,只需要把变量写在url里面就可以了比如:

$ curl http://www.yahoo.com/login.cgi?user=nickwolfe&password=12345

而POST模式的option则是 -d

比如,

$ curl -d "user=nickwolfe&password=12345" http://www.yahoo.com/login.cgi

就相当于向这个站点发出一次登陆申请    ~

到底该用GET模式还是POST模式,要看对面服务器的程序设定。

一点需要注意的是,POST模式下的文件上的文件上传,比如

<form method="POST" enctype="multipar/form-data" action="http://cgi2.tky.3web.ne.jp/~zzh/up_file.cgi">
<input type=file name=upload>
<input type=submit name=nick value="go">
</form>

这样一个HTTP表单,我们要用curl进行模拟,就该是这样的语法:

$ curl -F upload=@localfile -F nick=go http://cgi2.tky.3web.ne.jp/~zzh/up_file.cgi

罗罗嗦嗦讲了这么多,其实curl还有很多很多技巧和用法比如 https的时候使用本地证书,就可以这样

$ curl -E localcert.pem https://remote_server

再比如,你还可以用curl通过dict协议去查字典    ~

$ curl dict://dict.org/d:computer

linux下载工具

12:30:00 PM 0 Comments

Linux常用下载工具推荐

关键词: linux    下载                                         

  Windows中有很多下载工具,如耳熟能详的FlashGet,NetAnt等。随着Linux的发展,特别是桌面应用的成熟,越来越多的用 户转向了Linux。面对网上丰富的下载资源,Linux用户如何下载呢?其实Linux下载和在Windows下载一样,都离不开下载工具。那 Linux中又有哪些下载工具呢?本文就为大家介绍Linux中常用的下载工具。图形界面下载工具     对于Linux初学者来说,图形化下载工具无疑是最佳选择。Linux提供了很多类似Windows中FlashGet、网络蚂蚁等下载工具,下面就为大 家详细介绍一下,希望大家能找到自己得力的下载工具。

  

   KGet     KGet是KDE默认的断点续传工具,通常无需安装。它界面简洁,操作方便,高效的拖拽下载功能最令人称道。比较遗憾的是它不支持代理服务器及 SOCKS5代理功能。功能上虽然不如FlashGet全面和强大,但对于日常下载已经绰绰有余了,推荐初学者使用,其界面如图1所示。

  选择"主选单"→"互联网"→"KGet"或直接使用"Alt+F2"快捷键并输入"kget"命令即可运行程序,其界面如图1所示。第一次使 用会弹出一个对话框,选择KGet的工作方式。可选择与Konqueror集成也可选择独立运行,不习惯使用Konqueror作浏览器的话,建议选择后 者。它的使用也非常的简单,在"打开"对话框中输入下载文件的地址,KGet就可下载了。更为方便的是拖拽下载,单击"拖放目标"按钮就会出现拖放标志, 只需将下载链接拖到该标志即可开始下载。KGet同网络蚂蚁一样也支持定时下载、下载完毕可设定自动断开连接或关机,具体设置方法为选择"设置"→"配置 KGet"→"自动"标签页并将相应选项选中,设定具体的时间和操作便可定时下载。 Gwget     Gwget是GNOME下常用的一个图形化下载工具。它是命令行下常用下载工具Wget的GTK图形化前端,具有Wget的全部功能,如断点续传、代理下 载等功能等。 1.安装 Gwget可到http://nchc.dl.sourceforge.net/sourceforge/gwget/gwget- 0.93.tar.gz下载,然后在终端中使用如下命令进行安装: #tar zxvf gwget-0.93.tar.gz #cd gwget-0.93/ #./configure #make #make install 2.设置     成功安装后便可在终端中运行"gwget"命令启动Gwget。图形界面操作起来十分便捷,具体下载操作只需将下载地址复制到"文件"→"URL"中即 可,单击"确定"按钮便可下载,图2便是下载中的Gwget。此外,在"编辑"→"首选项"中可设置Gwget的其他功能,如下载文件夹、限速、代理等。 由于Gwget和KGet使用上大同小异,这里就不作更详细地介绍了。

  Downloader for X     Downloader For X(文中简称为D4X)是Linux下功能强大的图形化下载工具。支持HTTP与FTP协议,具有类似NetAnt和FlashGet等多线程、断点续传 下载等功能。D4X还具有连接超时断点续传、记录下载日志、模拟下载、链接拖拽下载、自动复制剪贴板链接到下载地址栏中等功能。 1.下载和安装 D4X的下载地址为http://www.krasu.ru/soft/chuchelo/files/d4x-2.5.0final.tar.gz,下 载后使用如下命令安装: #tar zxvf d4x-2.5.0final.tar.gz #cd d4x-2.5.0final #./configure #make #make install 成功安装后,运行"d4x"命令便可直接运行。它的界面如图3所示,和FlashGet有点相像吧。

  2.使用和设置     D4X的使用十分简单,下载文件时,只需在"添加新的下载任务"对话框中输入下载文件地址即可。如果下载地址需要用户名和密码,可在这个对话框中直接输 入。如要计划下载,可在时间选项中设定下载时间。此外,在下载任务选项中,可设定一些下载的配置,如下载文件默认目录、默认线程个数、界面风格等。值得一 提是代理选项,可指定默认的代理服务器和SOCKS5代理,具体设置如图4所示。

  WxDfast     WxDfast也是一个图形化的下载工具,支持多线程、断点续传等功能,最大特点是下载速度快。可在 http://heanet.dl.sourceforge.net/sourceforge/dfast/wxdfast-0.2.1- src.tar.gz下载WxDfast的最新版本。然后使用如下命令进行安装: #tar jxvf wxdfast-0.2.1d.tar.bz2 #cd wxdfast-0.2.1-src #make install     在终端下运行"./wxdfast"命令便可运行程序。WxDfast界面非常简洁,其界面如图5所示。全英文界面使用起来可能不如KGet方便,好在它 的操作和KGet、D4X基本相同,大家可参照学习,这里就不赘述了。

  Aria     Aria是个小巧的多线程下载工具,简单易用的界面用起来得心应手。可在http://aria.rednoah.com /download_e.html下载最新版本,然后使用如下命令进行编译安装: #./configure #make #make install 成功安装后直接运行如下命令便可运行Aria: #aria& Aria的界面如图6所示,它的操作和D4X差不多,可参照使用。

                                           命令行下载工具   

       对于喜欢命令行操作及追求高效率、高速度下载的朋友,推荐使用命令行下载工具。命令行工具不但使用方便,而且大多具有很高的下载速度及下载效率,尤其适合于大批量下载文件。下面就为大家详细介绍一下这些工具。

   Wget Wget是一个十分常用命令行下载工具,多数Linux发行版本都默认包含这个工具。如果没有安装可在http://www.gnu.org /software/wget/wget.html下载最新版本,并使用如下命令编译安装: #tar zxvf wget-1.9.1.tar.gz #cd wget-1.9.1 #./configure #make #make install 它的用法很简单,Wget使用格式如下: #wget [选项] [下载地址] 1.Wget常用参数 ◆-b:后台下载,Wget默认的是把文件下载到当前目录。 ◆-O:将文件下载到指定的目录中。 ◆-P:保存文件之前先创建指定名称的目录。 ◆-t:尝试连接次数,当Wget无法与服务器建立连接时,尝试连接多少次。 ◆-c:断点续传,如果下载中断,那么连接恢复时会从上次断点开始下载。     除了上述常用功能,Wget还支持HTTP和FTP代理功能,编辑其配置文件"/etc/wgetrc"即可。具体方法是使用VI编辑器打开上述文件,将 "http_proxy"和"ftp_proxoy"前的#去掉,然后在这两项后输入相应的代理服务器的地址,保存退出即可。此外,Wget还可下载整个 网站,如下载http://man.chinaunix.net整个Man手册中心。只需输入如下命令即可: #wget -r -p -np -k http://man.chinaunix.net 其中-r参数是指使用递归下载,-p是指下载所有显示完整网页所以需要的文件,如图片等,-np是指不搜索上层目录,-k则是指将绝对链接转换为相对链 接。

   Prozilla     Prozilla也是一个十分流行的命令行下载工具,支持多线程下载和断点续传功能。可到http://prozilla.genesys.ro/下载最 新的1.3.7.4安装包,下载安装包后使用如下命令进行安装: #tar zxvf prozilla-1.3.7.4.tar.gz #cd prozilla-1.3.7.4 #./configure #make #make install Prozilla命令格式如下: #proz [参数] [下载地址] 常用的选项有: ◆-k=n :设置n个线程下载。不加此参数指定线程数,Prozilla默认为4线程下载。 ◆-P, –directory-prefix=DIR:指定将下载的文件保存在DIR/目录。 ◆-r, –resume:继续下载未完成的文件。如果要指定线程数下载可用如下命令: #proz -k=5 http://64.12.204.21/pub/mozilla.org/firefox/releases/1.0/linux-i686/zh-CN/firefox-1.0.installer.tar.gz 这样便以5线程进行文件的下载,并将文件保存到当前目录。和Wget一样,Prozilla也提供了续传功能,下载中断后,重新输入上述命令,就会出现提 示续传,按R键就可继续下载了。

   MyGet     MyGet目标设计成一个可扩展的,拥有丰富界面的多线程下载工具,它支持HTTP、FTP、HTTPS、MMS、RTSP等协议。在 http://myget.sourceforge.net/release/myget-0.1.0.tar.bz2下载其最新版本0.1.0,下载后 使用如下命令安装: #tar jxvf myget-0.1.0.tar.bz2 #cd myget-0.1.0 #./configure #make #make install MyGet命令格式如下: #mytget [选项] [下载地址] 常用的选项: ◆-d [目录]:指定下载到的文件在本地存放的位置,默认当前目录。 ◆-f [文件]:指定下载文件名称。 ◆-h:帮助选项。 ◆-n [线程数]:下载线程数量,默认为4个。 ◆-x [代理服务器地址]:设置代理服务器地址,如"-x http://user:password@host:port"。 MyGet常用的形式如下: #mytget -d /root/ -n 10 http://lumaqq.linuxsir.org/download/patch/lumaqq_2004t_patch_2005.07.21.00.00.zip Linuxdown     Linuxdown是一个命令行多线程下载工具,最多可支持30线程的下载。在https://gro.clinux.org/frs /download.php/1015/linuxdown-1.0.0.tar.gz下载最新的1.1.0版本。然后使用如下命令进行编译安装: #tar zxvf linuxdown-1.1.0.tar.gz #cd dandelion/ #make #make install linuxdown格式为: #linuxdown [下载地址] [选项] [线程数]     需要注意的是下载地址和选项都需要西文引号括起来,线程数不可超过30个。一个典型的下载如下: #linuxdown "http://lumaqq.linuxsir.org/download/patch/lumaqq_2004t_patch_2005.07.21.00.00.zip" 30

  Curl     Curl也是Linux下不错的命令行下载工具,小巧、高速,唯一的缺点是不支持多线程下载。在http://curl.haxx.se /download/curl-7.14.0.tar.gz下载最新版本。下载后便可使用如下命令编译安装: #tar zxvf curl-7.14.0.tar.gz #cd curl-7.14.0/ #./configure #make #make test #make install Curl使用格式如下: #curl [选项][下载地址] Curl典型下载如下: #curl -O http://10.1.27.10/~kennycx/tools/lumaqq_2004-linux_gtk2_x86_with_jre.tar.gz     使用Curl下载一个文件并保存到当前目录。此外,Curl虽然不支持多线程下载,但它可同时下载多个文件或下载文件的某一部分,可使用如下命令实现: #curl -r 0-199 http://www.netscape.com/ 获得文件的前200 bytes。     对于常用的代理下载Curl也可轻松实现,具体操作如下: #curl -x 10.1.27.10:1022 ftp://ftp.funet.fi/README 使用代理地址为10.1.27.10端口为1022的代理服务器下载一个文件。 #curl -U user:passwd -x 10.1.27.10:1022 ftp://ftp.funet.fi/README 如果代理服务器需要特别的验证,则需要在user:passwd处输入合法的帐号和密码。

  Axel     Axel是命令行下的多线程下载工具,支持断点续传,速度通常情况下是Wget的几倍。可在http://www.linuxfans.org/nuke /modules.php?name=Site_Downloads&op=mydown&did=1697下载。下载后使用如下命令编 译安装: #tar zxvf axel-1.0a.tar.gz #cd axel-1.0a/ #./configure #make #make install 基本的用法如下: #axel [选项] [下载目录] [下载地址] 一个典型下载如下: #alex -n 10 -o /home/kennycx/ http://10.1.27.10/~kennycx/tools/lumaqq_2004-linux_gtk2_x86_with_jre.tar.gz 用10线程将指定路径的文件下载到/home/kennycx/这个目录下。

     本文详细介绍了Linux中常用的下载工具,这些下载工具功能上各有千秋,使用上都比较简单,所以无论是初学者还是Linux高手总有一款适合你。

认识linux服务(关闭你不需要的服务)

8:31:00 PM 0 Comments

认识linux服务
请先阅读 Fedora 服务管理指南。了解什么是服务/后台进程(services/daemons),什么是运行级别(runlevels)以及各种用于管理服务(sevices)的工具。
你可以在命令行下使用 chkonfig 或 ntsysv 命令来管理服务(services),或者使用具有图形用户界面的 system-config-services 命令。GNOME 用户:系统-》管理-》服务器设置-》Services。
--------------------------------------------------------------------------------
单个服务介绍
现在我们介绍 Fedora Core 6 中所包含的各种服务(services)的功能,并提供使用建议。这不是一份详尽的清单。小心:不要关闭你不确定或不知道的服务(services)。
不要关闭以下服务(除非你有充足的理由):
acpid, haldaemon, messagebus, klogd, network, syslogd
请确定修改的是运行级别 3 和 5。
--------------------------------------------------------------------------------
NetworkManager, NetworkManagerDispatcher
NetworkManager 是一个自动切换网络连接的后台进程。很多笔记本用户都需要启用该功能,它让你能够在无线网络和有线网络之间切换。大多数台式机用户应该关闭该服务。一些 DHCP 用户可能需要开启它。
acpid
ACPI(全称 Advanced Configuration and Power Interface)服务是电源管理接口。建议所有的笔记本用户开启它。一些服务器可能不需要 acpi。支持的通用操作有:"电源开关","电池监视","笔记本 Lid 开关","笔记本显示屏亮度","休眠", "挂机",等等。
anacron, atd, cron
这几个调度程序有很小的差别。 建议开启 cron,如果你的电脑将长时间运行,那就更应该开启它。对于服务器,应该更深入了解以确定应该开启哪个调度程序。大多数情况下,笔记本/台式机应该关闭 atd 和 anacron。注意:一些任务的执行需要 anacron,比如:清理 /tmp 或 /var。
apmd
一些笔记本和旧的硬件使用 apmd。如果你的电脑支持 acpi,就应该关闭 apmd。如果支持 acpi,那么 apmd 的工作将会由 acpi 来完成。
autofs
该服务自动挂载可移动存储器(比如 USB 硬盘)。如果你使用移动介质(比如移动硬盘,U 盘),建议启用这个服务。
avahi-daemon, avahi-dnsconfd
Avahi 是 zeroconf 协议的实现。它可以在没有 DNS 服务的局域网里发现基于 zeroconf 协议的设备和服务。它跟 mDNS 一样。除非你有兼容的设备或使用 zeroconf 协议的服务,否则应该关闭它。我把它关闭。
bluetooth, hcid, hidd, sdpd, dund, pand
蓝牙(Bluetooth)是给无线便携设备使用的(非 wifi, 802.11)。很多笔记本提供蓝牙支持。有蓝牙鼠标,蓝牙耳机和支持蓝牙的手机。很多人都没有蓝牙设备或蓝牙相关的服务,所以应该关闭它。其他蓝牙相关 的服务有:hcid 管理所有可见的蓝牙设备,hidd 对输入设备(键盘,鼠标)提供支持, dund 支持通过蓝牙拨号连接网络,pand 允许你通过蓝牙连接以太网。
capi
仅仅对使用 ISDN 设备的用户有用。大多数用户应该关闭它。
cpuspeed
该服务可以在运行时动态调节 CPU 的频率来节约能源(省电)。许多笔记本的 CPU 支持该特性,现在,越来越多的台式机也支持这个特性了。如果你的 CPU 是:Petium-M,Centrino,AMD PowerNow, Transmetta,Intel SpeedStep,Athlon-64,Athlon-X2,Intel Core 2 中的一款,就应该开启它。如果你想让你的 CPU 以固定频率运行的话就关闭它。
cron
参见 anacron。
cupsd, cups-config-daemon
打印机相关。如果你有能在 Fedora 中驱动的 CUPS 兼容的打印机,你应该开启它。
dc_client, dc_server
磁盘缓存(Distcache)用于分布式的会话缓存。主要用在 SSL/TLS 服务器。它可以被 Apache 使用。大多数的台式机应该关闭它。
dhcdbd
这是一个让 DBUS 系统控制 DHCP 的接口。可以保留默认的关闭状态。
diskdump, netdump
磁盘转储(Diskdump)用来帮助调试内核崩溃。内核崩溃后它将保存一个 "dump" 文件以供分析之用。网络转储(Netdump)的功能跟 Diskdump 差不多,只不过它可以通过网络来存储。除非你在诊断内核相关的问题,它们应该被关闭。
dund
参见 bluetooth。
firstboot
该服务是 Fedora 安装过程特有的。它执行在安装之后的第一次启动时仅仅需要执行一次的特定任务。它可以被关闭。
gpm
终端鼠标指针支持(无图形界面)。如果你不使用文本终端(CTRL-ALT-F1, F2..),那就关闭它。不过,我在运行级别 3 开启它,在运行级别 5 关闭它。
hidd
参见 bluetooth。
hplip, hpiod, hpssd
HPLIP 服务在 Linux 系统上实现 HP 打印机支持,包括 Inkjet,DeskJet,OfficeJet,Photosmart,Business InkJet 和一部分 LaserJet 打印机。这是 HP 赞助的惠普 Linux 打印项目(HP Linux Printing Project)的产物。如果你有相兼容的打印机,那就启用它。
iptables
它是 Linux 标准的防火墙(软件防火墙)。如果你直接连接到互联网(如,cable,DSL,T1),建议开启它。如果你使用硬件防火墙(比如:D-Link,Netgear,Linksys 等等),可以关闭它。强烈建议开启它。
ip6tables
如果你不知道你是否在使用 IPv6,大部分情况下说明你没有使用。该服务是用于 IPv6 的软件防火墙。大多数用户都应该关闭它。阅读这里了解如何关闭 Fedora 的 IPv6 支持。
irda, irattach
IrDA 提供红外线设备(笔记本,PDA's,手机,计算器等等)间的通讯支持。大多数用户应该关闭它。
irqbalance
在多处理器系统中,启用该服务可以提高系统性能。大多数人不使用多处理器系统,所以关闭它。但是我不知道它作用于多核 CPU's 或 超线程 CPU's 系统的效果。在单 CPU 系统中关闭它应该不会出现问题。
isdn
这是一种互联网的接入方式。除非你使用 ISDN 猫来上网,否则你应该关闭它。
kudzu
该服务进行硬件探测,并进行配置。如果更换硬件或需要探测硬件更动,开启它。但是绝大部分的台式机和服务器都可以关闭它,仅仅在需要时启动。
lm_sensors
该服务可以探测主板感应器件的值或者特定硬件的状态(一般用于笔记本电脑)。你可以通过它来查看电脑的实时状态,了解电脑的健康状况。它在 GKrellM 用户中比较流行。查看 lm_sensors 的主页获得更多信息。如果没有特殊理由,建议关闭它。
mctrans
如果你使用 SELinux 就开启它。默认情况下 Fedora Core 开启 SELinux。
mdmonitor
该服务用来监测 Software RAID 或 LVM 的信息。它不是一个关键性的服务,可以关闭它。
mdmpd
该服务用来监测 Multi-Path 设备(该类型的存储设备能被一种以上的控制器或方法访问)。它应该被关闭。
messagebus
这是 Linux 的 IPC(Interprocess Communication,进程间通讯)服务。确切地说,它与 DBUS 交互,是重要的系统服务。强烈建议开启它。
netdump
参见 diskdump。
netplugd
Netplugd 用于监测网络接口并在接口状态改变时执行指定命令。建议保留它的默认关闭状态。
netfs
该服务用于在系统启动时自动挂载网络中的共享文件空间,比如:NFS,Samba 等等。如果你连接到局域网中的其它服务器并进行文件共享,就开启它。大多数台式机和笔记本用户应该关闭它。
nfs, nfslock
这是用于 Unix/Linux/BSD 系列操作系统的标准文件共享方式。除非你需要以这种方式共享数据,否则关闭它。
ntpd
该服务通过互联网自动更新系统时间。如果你能永久保持互联网连接,建议开启它,但不是必须的。
pand
参见 bluetooth。
pcscd
该服务提供智能卡(和嵌入在信用卡,识别卡里的小芯片一样大小)和智能卡读卡器支持。如果你没有读卡器设备,就关闭它。
portmap
该服务是 NFS(文件共享)和 NIS(验证)的补充。除非你使用 NFS 或 NIS 服务,否则关闭它。
readahead_early, readahead_later
该服务通过预先加载特定的应用程序到内存中以提供性能。如果你想程序启动更快,就开启它。
restorecond
用于给 SELinux 监测和重新加载正确的文件上下文(file contexts)。它不是必须的,但如果你使用 SELinux 的话强烈建议开启它。
rpcgssd, rpcidmapd, rpcsvcgssd
用于 NFS v4。除非你需要或使用 NFS v4,否则关闭它。
sendmail
除非你管理一个邮件服务器或你想在局域网内传递或支持一个共享的 IMAP 或 POP3 服务。大多数人不需要一个邮件传输代理。如果你通过网页(hotmail/yahoo/gmail)或使用邮件收发程序(比 如:Thunderbird,Kmail,Evolution 等等)收发程序。你应该关闭它。
smartd
SMART Disk Monitoring 服务用于监测并预测磁盘失败或磁盘问题(前提:磁盘必须支持 SMART)。大多数的桌面用户不需要该服务,但建议开启它,特别是服务器。
smb
SAMBA 服务是在 Linux 和 Windows 之间共享文件必须的服务。如果有 Windows 用户需要访问 Linux 上的文件,就启用它。查看如何在 Fedora Core 6 下配置 Samba。
sshd
SSH 允许其他用户登录到你的系统并执行程序,该用户可以和你同一网络,也可以是远程用户。开启它存在潜在的安全隐患。如果你不需要从其它机器或不需要从远程登录,就应该关闭它。
xinetd
(该服务默认可能不被安装)它是一个特殊的服务。它可以根据特定端口收到的请求启动多个服务。比如:典型的 telnet 程序连接到 23 号端口。如果有 telent 请求在 23 号端口被 xinetd 探测到,那 xinetd 将启动 telnetd 服务来响应该请求。为了使用方便,可以开启它。运行 chkconfig --list, 通过检查 xinetd 相关的输出可以知道有哪些服务被 xinetd 管理。

awk详解

11:57:00 AM 0 Comments

awk详解

awk详解
a w k是一种程序语言,对文档资料的处理具有很强的功能。awk 名称是由它三个最初设计
者的姓氏的第一个字母而命名的: Alfred V. Aho、Peter J. We i n b e rg e r、Brian W. Kernighan。
a w k最初在1 9 7 7年完成。1 9 8 5年发表了一个新版本的a w k,它的功能比旧版本增强了不少。a w k
能够用很短的程序对文档里的资料做修改、比较、提取、打印等处理。如果使用C 或P a s c a l
等语言编写程序完成上述的任务会十分不方便而且很花费时间,所写的程序也会很大。
a w k不仅仅是一个编程语言,它还是L i n u x系统管理员和程序员的一个不可缺少的工具。
a w k语言本身十分好学,易于掌握,并且特别的灵活。
gawk 是G N U计划下所做的a w k,gawk 最初在1 9 8 6年完成,之后不断地被改进、更新。
gawk 包含awk 的所有功能。
6.1 gawk的主要功能
gawk 的主要功能是针对文件的每一行( l i n e ),也就是每一条记录,搜寻指定的格式。当某
一行符合指定的格式时,gawk 就会在此行执行被指定的动作。gawk 依此方式自动处理输入文
件的每一行直到输入文件档案结束。
g a w k经常用在如下的几个方面:
? 根据要求选择文件的某几行,几列或部分字段以供显示输出。
? 分析文档中的某一个字出现的频率、位置等。
? 根据某一个文档的信息准备格式化输出。
? 以一个功能十分强大的方式过滤输出文档。
? 根据文档中的数值进行计算。
6.2 如何执行gawk程序
基本上有两种方法可以执行g a w k程序。
如果gawk 程序很短,则可以将gawk 直接写在命令行,如下所示:
gawk 'program' input-file1 input-file2 ...
其中program 包括一些pattern 和a c t i o n。
如果gawk 程序较长,较为方便的做法是将gawk 程序存在一个文件中,
gawk 的格式如下所示:
gawk -f program-file input-file1 input-file2 ...
gawk 程序的文件不止一个时,执行gawk 的格式如下所示:
gawk -f program-file1 -f program-file2 ... input-file1 input-file2 ...
6.3 文件、记录和字段
一般情况下,g a w k可以处理文件中的数值数据,但也可以处理字符串信息。如果数据没有
存储在文件中,可以通过管道命令和其他的重定向方法给g a w k提供输入。当然, g a w k只能处
理文本文件(A S C I I码文件)。
电话号码本就是一个g a w k可以处理的文件的简单例子。电话号码本由很多条目组成,每一
个条目都有同样的格式:姓、名、地址、电话号码。每一个条目都是按字母顺序排列。
在g a w k中,每一个这样的条目叫做一个记录。它是一个完整的数据的集合。例如,电话号
码本中的Smith John这个条目,包括他的地址和电话号码,就是一条记录。
记录中的每一项叫做一个字段。在g a w k中,字段是最基本的单位。多个记录的集合组成了
一个文件。
大多数情况下,字段之间由一个特殊的字符分开,像空格、TA B、分号等。这些字符叫做
字段分隔符。请看下面这个/ e t c / p a s s w d文件:
t p a r k e r ; t 3 6 s 6 2 h s h ; 5 0 1 ; 1 0 1 ; Tim Parker;/home/tparker;/bin/bash
etreijs;2ys639dj3h;502;101;Ed Tr e i j s ; / h o m e / e t r e i j s ; / b i n / t c s h
y c h o w ; 1 h 2 7 s j ; 5 0 3 ; 1 0 1 ; Yvonne Chow;/home/ychow;/bin/bash
你可以看出/ e t c / p a s s w d文件使用分号作为字段分隔符。/ e t c / p a s s w d文件中的每一行都包括
七个字段:用户名;口令;用户I D;工作组I D;注释; h o m e目录;启始的外壳。如果你想要
查找第六个字段,只需数过五个分号即可。
但考虑到以下电话号码本的例子,你就会发现一些问题:
Smith John 13 Wilson St. 555-1283
Smith John 2736 Artside Dr Apt 123 555-2736
Smith John 125 Westmount Cr 555-1726
虽然我们能够分辨出每个记录包括四个字段,但g a w k却无能为力。电话号码本使用空格作
为分隔符,所以g a w k认为S m i t h是第一个字段, John 是第二个字段,1 3是第三个字段,依次类
推。就g a w k而言,如果用空格作为字段分隔符的话,则第一个记录有六个字段,而第二个记
录有八个字段。
所以,我们必须找出一个更好的字段分隔符。例如,像下面一样使用斜杠作为字段分隔
符:
Smith/John/13 Wilson St./555-1283
Smith/John/2736 Artside Dr/Apt/123/555-2736
Smith/John/125 Westmount Cr/555-1726
如果你没有指定其他的字符作为字段分隔符,那么g a w k将缺省地使用空格或TA B作为字段
分隔符。
6.4 模式和动作
在g a w k语言中每一个命令都由两部分组成:一个模式( p a t t e r n)和一个相应的动作
(a c t i o n)。只要模式符合,g a w k就会执行相应的动作。其中模式部分用两个斜杠括起来,而动
作部分用一对花括号括起来。例如:
/ p a t t e r n 1 / { a c t i o n 1 }
/ p a t t e r n 2 / { a c t i o n 2 }
/ p a t t e r n 3 / { a c t i o n 3 }
所有的g a w k程序都是由这样的一对对的模式和动作组成的。其中模式或动作都能够被省
略,但是两个不能同时被省略。如果模式被省略,则对于作为输入的文件里面的每一行,动作
都会被执行。如果动作被省略,则缺省的动作被执行,既显示出所有符合模式的输入行而不做
任何的改动。
下面是一个简单的例子,因为gawk 程序很短,所以将gawk 程序直接写在外壳命令行:
gawk '/tparker/' /etc/passwd
此程序在上面提到的/ e t c / p a s s w d文件中寻找符合t p a r k e r模式的记录并显示(此例中没有动
作,所以缺省的动作被执行)。
让我们再看一个例子:
gawk '/UNIX/{print $2}' file2.data
此命令将逐行查找f i l e 2 . d a t a文件中包含U N I X的记录,并打印这些记录的第二个字段。
你也可以在一个命令中使用多个模式和动作对,例如:
gawk '/scandal/{print $1} /rumor/{print $2}' gossip_file
此命令搜索文件g o s s i p _ f i l e中包括s c a n d a l的记录,并打印第一个字段。然后再从头搜索
g o s s i p _ f i l e中包括r u m o r的记录,并打印第二个字段。
6.5 比较运算和数值运算
g a w k有很多比较运算符,下面列出重要的几个:
= = 相等
! = 不相等
> 大于
< 小于
> = 大于等于
< = 小于等于
例如:
gawk '$4 > 100' testfile
将会显示文件testfile 中那些第四个字段大于1 0 0的记录。
下表列出了g a w k中基本的数值运算符。
运算符说明示例
+ 加法运算2+6
- 减法运算6-3
* 乘法运算2*5
/ 除法运算8/4
^ 乘方运算3^2 (=9)
% 求余数9%4 (=1)
例如:
{print $3/2}
显示第三个字段被2除的结果。
在g a w k中,运算符的优先权和一般的数学运算的优先权一样。例如:
{print $1+$2*$3}
显示第二个字段和第三个字段相乘,然后和第一个字段相加的结果。
你也可以用括号改变优先次序。例如:
{print ($1+$2)*$3}
显示第一个字段和第二个字段相加,然后和第三个字段相乘的结果。
6.6 内部函数
g a w k中有各种的内部函数,现在介绍如下:
6.6.1 随机数和数学函数
sqrt(x) 求x 的平方根
sin(x) 求x 的正弦函数
cos(x) 求x 的余弦函数
a t a n 2 ( x,y) 求x / y的余切函数
log(x) 求x 的自然对数
exp(x) 求x 的e 次方
int(x) 求x 的整数部分
rand() 求0 和1之间的随机数
srand(x) 将x 设置为r a n d ( )的种子数
6.6.2 字符串的内部函数
? i n d e x ( i n,find) 在字符串in 中寻找字符串find 第一次出现的地方,返回值是字符串
find 出现在字符串in 里面的位置。如果在字符串in 里面找不到字符串f i n d,则返回值为
0。
例如:
print index("peanut"," a n " )
显示结果3。
? length(string) 求出string 有几个字符。
例如:
l e n g t h ( " a b c d e " )
显示结果5。
? m a t c h ( s t r i n g,r e g e x p ) 在字符串string 中寻找符合regexp 的最长、最靠左边的子字
符串。返回值是regexp 在string 的开始位置,即i n d e x值。match 函数将会设置系统变量
R S TA RT 等于i n d e x的值,系统变量RLENGTH 等于符合的字符个数。如果不符合,则会
设置R S TA RT 为0、RLENGTH 为- 1。
? s p r i n t f ( f o r m a t,e x p r e s s i o n 1,. . . ) 和printf 类似,但是sprintf 并不显示,而是返回字符
串。
例如:
sprintf("pi = %.2f (approx.)",2 2 / 7 )
返回的字符串为pi = 3.14 (approx.)
? s u b ( r e g e x p,r e p l a c e m e n t,t a rg e t ) 在字符串t a rget 中寻找符合regexp 的最长、最靠左的
地方,以字串replacement 代替最左边的r e g e x p。
例如:
str = "water,w a t e r,e v e r y w h e r e "
s u b ( / a t /, " i t h ",s t r )
结果字符串s t r会变成
w i t h e r,w a t e r,e v e r y w h e r e
? g s u b ( r e g e x p,r e p l a c e m e n t,t a rget) 与前面的s u b类似。在字符串t a rget 中寻找符合
r e g e x p的所有地方,以字符串replacement 代替所有的r e g e x p。
例如:
s t r = " w a t e r,w a t e r,e v e r y w h e r e "g s u b ( / a t /, " i t h ",s t r )
结果字符串s t r会变成
w i t h e r,w i t h e r,e v e r y w h e r e
? s u b s t r ( s t r i n g,s t a r t,length) 返回字符串string 的子字符串,这个子字符串的长度为
l e n g t h,从第start 个位置开始。
例如:
s u b s t r ( " w a s h i n g t o n ",5,3 )
返回值为i n g
如果没有length ,则返回的子字符串是从第start 个位置开始至结束。
例如:
s u b s t r ( " w a s h i n g t o n ",5 )
返回值为i n g t o n。
? tolower(string) 将字符串s t r i n g的大写字母改为小写字母。
例如:
tolower("MiXeD cAsE 123")
返回值为mixed case 123。
? toupper(string) 将字符串s t r i n g的小写字母改为大写字母。
例如:
toupper("MiXeD cAsE 123")
返回值为MIXED CASE 123。
6.6.3 输入输出的内部函数
? close(filename) 将输入或输出的文件filename 关闭。
? system(command) 此函数允许用户执行操作系统的指令,执行完毕后将回到g a w k程
序。
例如:
BEGIN {system("ls")}
6.7 字符串和数字
字符串就是一连串的字符,它可以被g a w k逐字地翻译。字符串用双引号括起来。数字不能
用双引号括起来,并且g a w k将它当作一个数值。例如:
gawk '$1 != "Tim" {print}' testfile
此命令将显示第一个字段和Ti m不相同的所有记录。如果命令中Ti m两边不用双引号,
g a w k将不能正确执行。
再如:
gawk '$1 == "50" {print}' testfile
此命令将显示所有第一个字段和5 0这个字符串相同的记录。g a w k不管第一字段中的数值
的大小,而只是逐字地比较。这时,字符串5 0和数值5 0并不相等。
6.8 格式化输出
我们可以让动作显示一些比较复杂的结果。例如:
gawk '$1 != "Tim" {print $1,$ 5,$ 6,$2}' testfile
将显示t e s t f i l e文件中所有第一个字段和Ti m不相同的记录的第一、第五、第六和第二个字
段。
进一步,你可以在p r i n t动作中加入字符串,例如:
gawk '$1 != "Tim" {print "The entry for ",$ 1,"is not Tim. ",$2}' testfile
p r i n t动作的每一部分用逗号隔开。
借用C语言的格式化输出指令,可以让g a w k的输出形式更为多样。这时,应该用p r i n t f而不
是p r i n t。例如:
{printf "%5s likes this language\n",$ 2 }
p r i n t f中的%5s 部分告诉gawk 如何格式化输出字符串,也就是输出5个字符长。它的值由
printf 的最后部分指出,在此是第二个字段。\ n是回车换行符。如果第二个字段中存储的是人
名,则输出结果大致如下:
Tim likes this language
G e o ff likes this language
Mike likes this language
Joe likes this language
gawk 语言支持的其他格式控制符号如下:
? c 如果是字符串,则显示第一个字符;如果是整数,则将数字以ASCII 字符的形式显示。
例如:
printf "% c",6 5
结果将显示字母A。
? d 显示十进制的整数。
? i 显示十进制的整数。
? e 将浮点数以科学记数法的形式显示。
例如:
print "$ 4 . 3 e",1 9 5 0
结果将显示1 . 9 5 0 e + 0 3。
? f 将数字以浮点的形式显示。
? g 将数字以科学记数法的形式或浮点的形式显示。数字的绝对值如果大于等于0 . 0 0 0 1则
以浮点的形式显示,否则以科学记数法的形式显示。
? o 显示无符号的八进制整数。
? s 显示一个字符串。
? x 显示无符号的十六进制整数。1 0至1 5以a至f表示。
? X 显示无符号的十六进制整数。1 0至1 5以A至F表示。
? % 它并不是真正的格式控制字符,% %将显示%。
当你使用这些格式控制字符时,你可以在控制字符前给出数字,以表示你将用的几位或几
个字符。例如,6 d表示一个整数有6位。再请看下面的例子:
{printf "%5s works for %5s and earns %2d an hour",$ 1,$ 2,$ 3 }
将会产生类似如下的输出:
Joe works for Mike and earns 12 an hour
当处理数据时,你可以指定数据的精确位数
{printf "%5s earns $%.2f an hour",$ 3,$ 6 }
其输出将类似于:
Joe earns $12.17 an hour
你也可以使用一些换码控制符格式化整行的输出。之所以叫做换码控制符,是因为g a w k对
这些符号有特殊的解释。下面列出常用的换码控制符:
\a 警告或响铃字符。
\b 后退一格。
\f 换页。
\n 换行。
\r 回车。
\t Ta b。
\v 垂直的t a b。
6.9 改变字段分隔符
在g a w k中,缺省的字段分隔符一般是空格符或TA B。但你可以在命令行使用- F选项改变字
符分隔符,只需在- F后面跟着你想用的分隔符即可。
gawk -F" ;"'/tparker/{print}' /etc/passwd
在此例中,你将字符分隔符设置成分号。注意: - F必须是大写的,而且必须在第一个引号
之前。
6.10 元字符
g a w k语言在格式匹配时有其特殊的规则。例如, c a t能够和记录中任何位置有这三个字符
的字段匹配。但有时你需要一些更为特殊的匹配。如果你想让c a t只和c o n c a t e n a t e匹配,则需要
在格式两端加上空格:
/ cat / {print}
再例如,你希望既和c a t又和C AT匹配,则可以使用或(|):
/ cat | CAT / {print}
在g a w k中,有几个字符有特殊意义。下面列出可以用在g a w k格式中的这些字符:
? ^ 表示字段的开始。
例如:
$3 ~ /^b/
如果第三个字段以字符b开始,则匹配。
? $ 表示字段的结束。
例如:
$3 ~ /b$/
如果第三个字段以字符b结束,则匹配。
? . 表示和任何单字符m匹配。
例如:
$3 ~ /i.m/
如果第三个字段有字符i,则匹配。
? | 表示"或"。
例如:
/ c a t | C AT/
和cat 或C AT字符匹配。
? * 表示字符的零到多次重复。
例如:
/UNI*X/
和U N X、U N I X、U N I I X、U N I I I X等匹配。
? + 表示字符的一次到多次重复。
例如:
/UNI+X/
和U N I X、U N I I X等匹配。
? \{a,b\} 表示字符a次到b次之间的重复。
例如:
/ U N I \ { 1,3 \ } X
和U N I X、U N I I X和U N I I I X匹配。
? ? 表示字符零次和一次的重复。
例如:
/UNI?X/
和UNX 和U N I X匹配。
? [] 表示字符的范围。
例如:
/I[BDG]M/
和I B M、I D M和I G M匹配
? [^] 表示不在[ ]中的字符。
例如:
/I[^DE]M/
和所有的以I开始、M结束的包括三个字符的字符串匹配,除了I D M和I E M之外。
6.11 调用gawk程序
当需要很多对模式和动作时,你可以编写一个g a w k程序(也叫做g a w k脚本)。在g a w k程序
中,你可以省略模式和动作两边的引号,因为在g a w k程序中,模式和动作从哪开始和从哪结
束时是很显然的。
你可以使用如下命令调用g a w k程序:
gawk -f script filename
此命令使g a w k对文件f i l e n a m e执行名为s c r i p t的g a w k程序。
如果你不希望使用缺省的字段分隔符,你可以在f选项后面跟着F选项指定新的字段分隔符
(当然你也可以在g a w k程序中指定),例如,使用分号作为字段分隔符:
gawk -f script -F";" filename
如果希望gawk 程序处理多个文件,则把各个文件名罗列其后:
gawk -f script filename1 filename2 filename3 ...
缺省情况下, g a w k的输出将送往屏幕。但你可以使用L i n u x的重定向命令使g a w k的输出送
往一个文件:
gawk -f script filename > save_file
6.12 BEGIN和END
有两个特殊的模式在g a w k中非常有用。B E G I N模式用来指明g a w k开始处理一个文件之前执行一些动作。B E G I N经常用来初始化数值,设置参数等。E N D模式用来在文件处理完成后
执行一些指令,一般用作总结或注释。
BEGIN 和E N D中所有要执行的指令都应该用花括号括起来。BEGIN 和E N D必须使用大写。
请看下面的例子:
BEGIN { print "Starting the process the file" }
$1 == "UNIX" {print}
$2 > 10 {printf "This line has a value of %d",$ 2 }
END { print "Finished processing the file. Bye!"}
此程序中,先显示一条信息: Starting the process the file,然后将所有第一个字段等于
U N I X的整条记录显示出来,然后再显示第二个字段大于10 的记录,最后显示信息: F i n i s h e d
processing the file. Bye!。
6.13 变量
在g a w k中,可以用等号( = )给一个变量赋值:
var1 = 10
在g a w k中,你不必事先声明变量类型。
请看下面的例子:
$1 == "Plastic" { count = count + 1 }
如果第一个字段是P l a s t i c,则c o u n t的值加1。在此之前,我们应当给c o u n t赋予过初值,一
般是在B E G I N部分。
下面是比较完整的例子:
BEGIN { count = 0 }
$5 == "UNIX" { count = count + 1 }
END { printf "%d occurrences of UNIX were found",count }
变量可以和字段和数值一起使用,所以,下面的表达式均为合法:
count = count + $6
count = $5 - 8
count = $5 + var1
变量也可以是格式的一部分,例如:
$2 > max_value {print "Max value exceeded by ",$2 - max_value}
$4 - var1 < min_value {print "Illegal value of ",$ 4 }
6.14 内置变量
g a w k语言中有几个十分有用的内置变量,现在列于下面:
NR 已经读取过的记录数。
FNR 从当前文件中读出的记录数。
F I L E N A M E 输入文件的名字。
FS 字段分隔符(缺省为空格)。
RS 记录分隔符(缺省为换行)。
OFMT 数字的输出格式(缺省为% g)。
OFS 输出字段分隔符。
ORS 输出记录分隔符。
NF 当前记录中的字段数。
如果你只处理一个文件,则NR 和FNR 的值是一样的。但如果是多个文件, N R是对所有
的文件来说的,而FNR 则只是针对当前文件而言。
例如:
NR <= 5 {print "Not enough fields in the record"}
检查记录数是否小于5,如果小于5,则显示出错信息。
F S十分有用,因为F S控制输入文件的字段分隔符。例如,在B E G I N格式中,使用如下的
命令:
F S = " : "
6.15 控制结构
6.15.1 if 表达式
if 表达式的语法如下:
if (expression){
c o m m a n d s
}
e l s e {
c o m m a n d s
}
例如:
# a simple if loop
(if ($1 == 0){
print "This cell has a value of zero"
}
else {
printf "The value is %d\n",$ 1
} )
再看下一个例子:
# a nicely formatted if loop
(if ($1 > $2){
print "The first column is larger"
}
else {
print "The second column is larger"
} )
6.15.2 while 循环
while 循环的语法如下:
while (expression){
c o m m a n d s
}
例如:
# interest calculation computes compound interest
# inputs from a file are the amount,interest_rateand years
{var = 1
while (var <= $3) {
p r i n t f ( " % f \ n ",$ 1 * ( 1 + $ 2 ) ^ v a r )
v a r + +}
}
6.15.3 for 循环
for 循环的语法如下:
for (initialization; expression; increment) {
c o m m a n d
}
例如:
# interest calculation computes compound interest
# inputs from a file are the amount,interest_rateand years
{for (var=1; var <= $3; var++) {
p r i n t f ( " % f \ n ",$ 1 * ( 1 + $ 2 ) ^ v a r )
}
}
6.15.4 next 和exit
next 指令用来告诉gawk 处理文件中的下一个记录, 而不管现在正在做什么。语法如下:
{ command1
c o m m a n d 2
c o m m a n d 3
n e x t
c o m m a n d 4
}
程序只要执行到n e x t指令,就跳到下一个记录从头执行命令。因此,本例中, c o m m a n d 4
指令永远不会被执行。
程序遇到e x i t指令后,就转到程序的末尾去执行E N D,如果有E N D的话。
6.16 数组
g a w k语言支持数组结构。数组不必事先初始化。声明一个数组的方法如下:
a r r a y n a m e [ n u m ] = v a l u e
请看下面的例子:
# reverse lines in a file
{line[NR] = $0 } # remember each line
END {var=NR # output lines in reverse order
while (var > 0){
print line[var]
v a r - -
}
}
此段程序读取一个文件的每一行,并用相反的顺序显示出来。我们使用N R作为数组的下
标来存储文件的每一条记录,然后在从最后一条记录开始,将文件逐条地显示出来。
6.17 用户自定义函数
复杂的gawk 程序常常可以使用自己定义的函数来简化。调用用户自定义函数与调用内部
函数的方法一样。函数的定义可以放在gawk 程序的任何地方。
用户自定义函数的格式如下:
function name (parameter-list) {
b o d y - o f - f u n c t i o n
}
name 是所定义的函数的名称。一个正确的函数名称可包括一序列的字母、数字、下标线
( u n d e r s c o r e s ),但是不可用数字做开头。p a r a m e t e r-list 是函数的全部参数的列表,各个参数之
间以逗点隔开。body-of-function 包含gawk 的表达式,它是函数定义里最重要的部分,它决定
函数实际要做的事情。
下面这个例子,会将每个记录的第一个字段的值的平方与第二个字段的值的平方加起来。
{print "sum =",S q u a r e S u m ( $ 1,$ 2 ) }
function SquareSum(x,y) {
s u m = x * x + y * y
return sum
}
到此,我们已经知道了g a w k的基本用法。g a w k语言十分易学好用,例如,你可以用g a w k
编写一段小程序来计算一个目录中所有文件的个数和容量。如果用其他的语言,如C语言,则
会十分的麻烦,相反,g a w k只需要几行就可以完成此工作。
6.18 几个实例
最后,再举几个g a w k的例子:
gawk '{if (NF > max) max = NF}
END {print max}'
此程序会显示所有输入行之中字段的最大个数。
gawk 'length($0) > 80'
此程序会显示出超过80 个字符的每一行。此处只有模式被列出,动作是采用缺省值显示
整个记录。
gawk 'NF > 0'
显示拥有至少一个字段的所有行。这是一个简单的方法,将一个文件里的所有空白行删除。
gawk 'BEGIN {for (i = 1; i <= 7; i++)
print int(101 * rand())}'
此程序会显示出范围是0 到100 之间的7 个随机数。
ls -l files | gawk '{x += $4}; END {print "total bytes: " x}'
此程序会显示出所有指定的文件的总字节数。
expand file | gawk '{if (x < length()) x = length()}
END {print "maximum line length is " x}'
此程序会将指定文件里最长一行的长度显示出来。expand 会将tab 改成s p a c e,所以是用
实际的右边界来做长度的比较。
gawk 'BEGIN {FS = ":"}
{print $1 | "sort"}' /etc/passwd
此程序会将所有用户的登录名称,依照字母的顺序显示出来。
gawk '{nlines++}
END {print nlines}'
此程序会将一个文件的总行数显示出来。
gawk 'END {print NR}'
此程序也会将一个文件的总行数显示出来,但是计算行数的工作由g a w k来做。
gawk '{print NR,$ 0 } '
此程序显示出文件的内容时,会在每行的最前面显示出行号,它的函数与' cat -n'类似。
function name (parameter-list) {
b o d y - o f - f u n c t i o n
}
name 是所定义的函数的名称。一个正确的函数名称可包括一序列的字母、数字、下标线
( u n d e r s c o r e s ),但是不可用数字做开头。p a r a m e t e r-list 是函数的全部参数的列表,各个参数之
间以逗点隔开。body-of-function 包含gawk 的表达式,它是函数定义里最重要的部分,它决定
函数实际要做的事情。
下面这个例子,会将每个记录的第一个字段的值的平方与第二个字段的值的平方加起来。
{print "sum =",S q u a r e S u m ( $ 1,$ 2 ) }
function SquareSum(x,y) {
s u m = x * x + y * y
return sum
}
到此,我们已经知道了g a w k的基本用法。g a w k语言十分易学好用,例如,你可以用g a w k
编写一段小程序来计算一个目录中所有文件的个数和容量。如果用其他的语言,如C语言,则
会十分的麻烦,相反,g a w k只需要几行就可以完成此工作。
6.18 几个实例
最后,再举几个g a w k的例子:
gawk '{if (NF > max) max = NF}
END {print max}'
此程序会显示所有输入行之中字段的最大个数。
gawk 'length($0) > 80'
此程序会显示出超过80 个字符的每一行。此处只有模式被列出,动作是采用缺省值显示
整个记录。
gawk 'NF > 0'
显示拥有至少一个字段的所有行。这是一个简单的方法,将一个文件里的所有空白行删除。
gawk 'BEGIN {for (i = 1; i <= 7; i++)
print int(101 * rand())}'
此程序会显示出范围是0 到100 之间的7 个随机数。
ls -l files | gawk '{x += $4}; END {print "total bytes: " x}'
此程序会显示出所有指定的文件的总字节数。
expand file | gawk '{if (x < length()) x = length()}
END {print "maximum line length is " x}'
此程序会将指定文件里最长一行的长度显示出来。expand 会将tab 改成s p a c e,所以是用
实际的右边界来做长度的比较。
gawk 'BEGIN {FS = ":"}
{print $1 | "sort"}' /etc/passwd
此程序会将所有用户的登录名称,依照字母的顺序显示出来。
gawk '{nlines++}
END {print nlines}'
此程序会将一个文件的总行数显示出来。
gawk 'END {print NR}'
此程序也会将一个文件的总行数显示出来,但是计算行数的工作由g a w k来做。
gawk '{print NR,$ 0 } '
此程序显示出文件的内容时,会在每行的最前面显示出行号,它的函数与' cat -n'类似。

HTTP Cookies

11:59:00 AM 0 Comments

HTTP Cookies

Http cookies provide the server with a mechanism to store and retrieve state information on the client application's system. This mechanism allows Web-based applications the ability to store information about selected items, user preferences, registration information, and other information that can be retrieved later.

Cookie-Related Headers

There are two headers, Set-Cookie and Cookie, that are related to cookies. The Set-Cookie header is sent by the server in response to an HTTP request, which is used to create a cookie on the user's system. The Cookie header is included by the client application with an HTTP request sent to a server, if there is a cookie that has a matching domain and path.

Set-Cookie Header

The Set-Cookie response header uses the following format:

Set-Cookie: <name>=<value>[; <name>=<value>]...
[; expires=<date>][; domain=<domain_name>]
[; path=<some_path>][; secure][; httponly]

One or more string sequences (separated by semicolons) that follow the pattern name=value must be included in the Set-Cookie response header. The server can use these string sequences to store data on the client's system.

The expiration date is set by using the format expires=date, where date is the expiration date in Greenwich Mean Time (GMT). If the expiration date is not set, the cookie expires after the Internet session ends. Otherwise, the cookie is persisted in the cache until the expiration date. The date must use the following format:

DAY, DD-MMM-YYYY HH:MM:SS GMT

DAY

The day of the week (Sun, Mon, Tue, Wed, Thu, Fri, Sat).

DD

The day in the month (such as 01 for the first day of the month).

MMM

The three-letter abbreviation for the month (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec).

YYYY

The year.

HH

The hour value in military time (22 would be 10:00 P.M., for example).

MM

The minute value.

SS

The second value.

Specifying the domain name, using the pattern domain=domain_name, is optional for persistent cookies and is used to indicate the end of the domain for which the cookie is valid. Session cookies that specify a domain are rejected. If the specified domain name ending matches the request, the cookie tries to match the path to determine if the cookie should be sent. For example, if the domain name ending is .microsoft.com, requests to home.microsoft.com and support.microsoft.com would be checked to see if the specified pattern matches the request. The domain name must have at least two or three periods in it to prevent cookies from being set for widely used domain name endings, such as .com, .edu, and co.jp. Allowable domain names would be similar to .microsoft.com, .someschool.edu, and .someserver.co.jp. Only hosts within the specified domain can set a cookie for a domain.

Setting the path, using the pattern path=some_path, is optional and can be used to specify a subset of the URLs for which the cookie is valid. If a path is specified, the cookie is considered valid for any requests that match that path. For example, if the specified path is /example, requests with the paths /examplecode and /example/code.htm would match. If no path is specified, the path is assumed to be the path of the resource associated with the Set-Cookie header.

The cookie can also be marked as secure, which specifies that the cookie can be sent only to https servers.

Finally, a cookie can be marked as HttpOnly (attributes are not case-sensitive), to indicate that the cookie is non-scriptable and should not be revealed to the client application, for security reasons. Within Windows Internet, this means that the cookie cannot be retrieved through the InternetGetCookie function.

Cookie Header

The Cookie header is included with any HTTP requests that have a cookie whose domain and path match the request. The Cookie header has the following format:

Cookie: <name>=<value> [;<name>=<value>]...

One or more string sequences, using the format name=value, contain the information that was set in the cookie.

Generating Cookies

There are three methods for generating cookies for Microsoft Internet Explorer: using Microsoft JScript, using the WinINet functions, and using a CGI script. All of the methods need to set the information that is included in the Set-Cookie header.

Generating a Cookie Using the DHTML Object Model

Using the Dynamic HTML (DHTML) object model, cookies can be set by calling the cookie property of the document object, as shown in the following example.

<SCRIPT language="JavaScript">
<!--
document.cookie = "SomeValueName = Some_Value";
-->
</SCRIPT>

Generating a Cookie Using the WinInet Functions

Cookies can be created by applications using the InternetSetCookie function. For more information, see Setting a Cookie.

Generating a Cookie Using a CGI Script

Cookies are generated by including a Set-Cookie header as part of a CGI script included in the HTTP response to a request.

The following example is a CGI script that includes a Set-Cookie header using Perl.

print "Set-Cookie:Test=test_value; 
expires=Sat, 01-Jan-2000 00:00:00 GMT;
path=/;"

expression 表达式

4:06:00 PM 0 Comments

Expression (programming)

From Wikipedia, the free encyclopedia

Jump to: navigation, search

An expression in a programming language is a combination of values, variables, operators, and functions that are interpreted (evaluated) according to the particular rules of precedence and of association for a particular programming language, which computes and then produces (returns, in a stateful environment) another value. The expression is said to evaluate to that value. As in math, the expression is (or can be said to have) its evaluated value; the expression is a representation of that value. So, in mathematics, an expression is a representation of a value.

Expressions may or may not have side effects. An expression with side effects does not normally have the property of referential transparency.

[edit] See also

Understanding swap files in Linux

11:05:00 AM 0 Comments


Understanding swap files in Linux
















To appease some of my hungrier
applications and support heftier development efforts, I recently
upgraded the memory on my system from 4 GiB to 8 GiB. That gave me
occasion to tinker around with the swapping behavior of my system and
check things out.



If you run anything close to a modern operating system, you almost certainly interact with a swap file.
You might be familiar with the basics of how these work: they allow
your OS to prioritize more frequently-used pages in main memory and
move the less frequently-used ones to disk. But there's a lot going on
underneath the covers. Here's a simple guide to the theory and practice
of swap files in Linux, and how you can tweak things for your benefit.



An abstract memory model



It'll be useful to have a mental model of the way memory works in general1, so we'll start from the basis of a simple one here.



In general, all computers have access to physical memory,
where the actual bits are manipulated and stored for use. Most modern
operating systems present physical memory to higher-level applications
as an abstraction called virtual memory. This allows
applications to see memory as if it were a contiguous block, even
though the underlying physical memory may theoretically be taken from
many arbitrary, heterogeneous sources -- multiple memory chips, flash
memory, disk drives, and so on.



The memory manager divides virtual memory into chunks of identical size called pages.
A page is the smallest amount that the OS will allocate in response to
requests from programs. It is also the smallest unit of transfer
between main memory and any other location, such as a hard disk. The
size of a page is usually fixed by the operating system's kernel2.



Applications
see virtual memory as a contiguous resource divided into units called
pages. A typical page size for a modern desktop system is about 4
kilobytes.


As pages are allocated to applications, they are assigned pages in the physical memory space through a special mapping called address translation. Applications don't know where they are in the physical space; they see only the pages they use.



Address translation maps virtual pages onto physical pages. This mapping is transparent to applications.


The memory manager knows how to aggregate different backing stores
to provide the abstraction of contiguous virtual memory. By updating
the address translation mechanism so that a virtual page always points
to the correct physical page, the memory manager may move pages around
in physical memory without directly impacting applications.



The backing stores for pages can be quite heterogeneous.


Wide variation in different kinds of physical memory



Not every backing store displays the same storage and speed
characteristics. If different types of physical memory display
different characteristics, the memory manager can exploit these
differences to optimize system performance. It can make intelligent
decisions about which pages should go where.



Consider the difference between main memory and a hard drive, for example.





characteristicstorage medium
on diskin main memory
absoluterelativeabsoluterelative
access time5ms10ns500,000× faster
peak transfer rate80 MB/s8 GB/s100× faster
storage space100 GB25× larger4 GB
price/GB storage$0.60/GB20× cheaper$12/GB


Some comparisons of a typical hard drive and typical main memory on a consumer-grade desktop.


Because storage on disk-backed file systems does indeed have
different characteristics than storage in main memory, there's
significant room to optimize depending on the characteristics of how
pages are accessed. As the table shows, hard disks are several orders
of magnitude slower and less efficient at retrieving data than main
memory. Thus, the memory manager needs to carefully balance the demand
for memory against the different kinds of supply.



Flavors of pages



If all pages were of the same kind, deciding which pages should go
where would be a simpler decision. For example, one strategy is to make
the access time quickest for the pages that are accessed the most
frequently. Unfortunately, it's not just the types of memory that are
heterogeneous, but also the contents of the pages that are stored
there. On Linux, there are four different kinds of pages.




  • Kernel pages. Pages holding the program contents of the
    kernel itself. Unlike the other flavors, these are fixed in memory once
    the operating system has loaded and are never moved.
  • Program pages. Pages storing the contents of programs and libraries. These are read-only, so no updates to disk are needed.
  • File-backed pages. Pages storing the contents of files on
    disk. If this page has been changed in memory (for example, if it's a
    document you're working on), it will eventually need to be written out
    to disk to synchronize the changes.
  • Anonymous pages. Pages not backed by anything on disk.
    When a program requests memory be allocated to perform computations or
    record information, the information resides in anonymous pages.




When the in-memory version of a page is the same as the one on disk, we say that the page is clean;
the contents are the same. But sometimes the contents of a page have
been updated since the last time they were read. When this happens, the
page becomes dirty.



A clean page can be repurposed for something else easily; no updates
need to be made, and the page can simply be recycled. But a dirty page
has to be written back to disk before it can be used again. For file
pages, this is an expensive operation, so the kernel tries to avoid the
overhead of flushing back to disk when it can.



For anonymous pages, there's a different problem. Effectively,
they're always dirty: the very act of creating the anonymous page means
that there is now data that is in memory which isn't in disk. If the
kernel wants to use anonymous pages for something else, it must first
reclaim them. But anonymous pages have no files to back them. How can
you flush something back to disk when there's nowhere to flush it to?



Swap files



The use of swap can resolve many of these issues. Swap is a disk-backed area that's treated as an extension of main memory. It serves as a holding area for pages that have been evicted by the kernel. Let's use an illustrative example to show how swap files help make memory work better.



Legend
for the next few diagrams. Unused pages have dotted borders; dirty
pages have an alert symbol; and anonymous and file pages are colored
orange and green, respectively.


When a moderately loaded system gets additional requests for memory,
the kernel generally draws from the pool of free pages first to fulfill
these requests. If there are few free pages remaining, the kernel tries
to flush clean pages to make room for the new requests.



The kernel prefers to go after unused pages first.


If the clean pages also become depleted, the kernel is forced to
clean a dirty page and then flush it. This is an expensive operation.
For this reason, the kernel tries to maintain at least some clean pages
all the time.



When the ratio of anonymous pages to dirty pages is high and the
number of clean pages is low, the kernel is running out of memory.
Without swap, this situation will require a number of costly disk
writes. Consider a request for allocation when a number of dirty pages
are already present.



Without swap space, it's easier for systems to get overloaded.


In the figure above, a request for two anonymous pages has come in.
There are no more unused pages, so the kernel must drop one of the
existing pages to satisfy the request. The kernel can use one page
freely: the single clean file page in slot 6.



But to allocate the second page, the kernel now has to flush one of
the dirty file pages (in slots 1, 3, or 4) back to disk to make room.
It cannot move the page in slot 5 anywhere, because it is anonymous and
has no backing store; there's nowhere else to put it. Even if this page
has not been used in a very long time, it must still occupy space in
memory until the process using it has released the page.



When
space is tight and there's no swap the kernel must make room by
cleaning dirty pages and freeing them. In this example, the kernel is
forced to clean page #1 back to disk to make room for the second
allocated page.


Without swap, the kernel gets boxed into this unfortunate corner more easily.



With swap, however, the kernel gets an additional tool to use in its
arsenal. Instead of being forced to clean one of the dirty pages, it
can instead evict one of the anonymous pages to the swap region.



When swap is available, the kernel doesn't need to clean dirty pages, and can instead move anonymous pages to swap.


As in the earlier non-swap scenario, the kernel use can use the
clean page in slot 6 for the first requested page. It is allocated and
the clean page is dropped.



For the second requested page, the kernel must no longer clean a
dirty page to make room. Instead, it can simply flush one of the
anonymous pages to the swap region. The code required to do this is
generally very simple and significantly less complex than cleaning a
dirty page, and the kernel prefers swapping to cleaning dirty
file-backed pages.



Optimizing your swap settings



Linux provides a number of ways to interact with your swap. Two are detailed here:




  • Aggressiveness of swapping
  • Adding and removing additional swap containers




Controlling aggressiveness of swapping



The more aggressively the kernel swaps, the more efficiently
existing memory can be put to use. Pages that look like they're not
being used will be swapped out rapidly. If the kernel swaps too often,
though, applications that were using those pages will take longer to
become responsive again as the kernel swaps their memory back into main
memory.



For a desktop user, responsiveness of applications can be important,
so an aggressive swap may not be desirable, even if it results in less
efficient use of memory. For servers and other non-interactive systems,
more aggressive swapping may be appropriate and acceptable.



On Linux, this careful balancing act can be configured to meet your
personal preferences. The kernel swaps out pages with a zealousness
controlled by a swappiness setting.



Swappiness is an integer that ranges from 0 to 100, and indicates
the degree to which the kernel favors swap space over main memory.
Higher swappiness means that the kernel will move things to swap more
frequently. Lower swappiness means that the kernel tries to avoid using
swap. A swappiness of zero causes the kernel to avoid swap for as long
as possible.



Ubuntu and several other Linux distributions have a default swappiness of 60. You can check your swap setting by reading a /proc/sys value:






$ cat /proc/sys/vm/swappiness
60





To temporarily modify your swappiness, simply edit this value:






$ sudo sysctl vm.swappiness=40
vm.swappiness = 40





This setting lasts until reboot or you change it again with another sysctl vm.swappiness invocation. To make this setting take effect on every reboot, edit your /etc/sysctl.conf configuration file.






$ gksudo gedit /etc/sysctl.conf





Find the vm.swappiness line; if none exists, add it.






vm.swappiness = 40





Adding swap containers



Modern operating systems generally have either a swap partition or a swap file.
In a swap partition, part of the hard drive is sliced off and becomes
dedicated to swap. A swap file is just an ordinary file that holds up
to its file size in swapped pages.



A swap file is considerably less complicated than a swap partition to establish. There is no speed difference between the two3,
so swap files are favorable in this respect. However, if you want to be
able to hibernate or suspend your computer, using a swap partition is
required in some cases. (These suspend/hibernate managers usually
cannot handle writing to an active file system.)



Making a new swap file is a simple process. In this example, we'll
make a 2 GiB swap file and make it available to the system as
additional swap space. We'll use primary.swap as the name
of the example swap file, but there is nothing special about the name
of the file or its extension. You may use anything you wish.



First, we need to create the swap file itself. We'll use a stream of zeroes as the input source (if=/dev/zero), and write it out to a file named primary.swap in the /mnt directory (of=/mnt/primary.swap). We will write 2048 (count=2048) blocks each 1 MiB in size (bs=1M). Depending on the speed of your hard disks, this may take a little while.






$ sudo dd if=/dev/zero of=/mnt/primary.swap bs=1M count=2048
2048+0 records in
2048+0 records out
2147483648 bytes (2.1 GB) copied, 30.1085 s, 71.3 MB/s





Next, we need to format this file and prepare it for use as a swapping space. The mkswap utility sets up a swap area on a device or file.






$ sudo mkswap /mnt/primary.swap
Setting up swapspace version 1, size = 2097148 KiB
no label, UUID=7be2b3b6-83b0-4afd-8537-197cf12f8c59





After formatting it, the swap can now be added to our system. Use the swapon utility to activate the swap region.






$ sudo swapon /mnt/primary.swap





You can verify that your swap space is now 2 GiB larger.






$ cat /proc/meminfo | grep SwapTotal
SwapTotal: 2097144 kB





Your changes will be lost at reboot, so if you want to make them permanent we'll need to edit your filesystem table in /etc/fstab.






$ gksudo gedit /etc/fstab





Now add your swap file to the list of filesystems to mount at boot by appending a line to the file.






/mnt/primary.swap  none  swap  sw  0 0





Removing a swap file



Removal works much the same way, but in reverse. If you've added your swap to the /etc/fstab list, you need to remove it here first.



To disable your running swaps, run the swapoff utility. You can either specify the swap you'd like to disable, or use the -a parameter.






$ sudo swapoff /mnt/primary.swap





When you disable swap, you force the kernel to clean every page on
the swap and/or push it back to main memory. If there is not enough
space to squeeze everything in, you may receive out of memory errors
from the kernel, so use this judiciously.



Conclusion



Swap files are an essential part of the memory-management modules of
operating systems. In Linux, adding and removing swap partitions and
files is simple, and you can control how the kernel interacts with swap
through configurable parameters. Through the use of these and other
techniques, and with an understanding of the basics of swap, you can
tweak your system's use of memory to your heart's content.



Additional reading




  • Speed up your system by avoiding the swap file. FOSSWire. Accessed February 8th, 2009.
  • 2.6 swapping behavior. LWN.net. Accessed February 8th, 2009.
  • Swap FAQ. Ubuntu Documentation. Accessed February 12th, 2009.
  • Patterson, David A. and Hennessy, John L. Computer Organization and Design: The hardware/software interface. © 1997. Morgan Kaufmann Publishers, San Francisco, California.




1 As this is only a model, we will naturally be leaving off some of the important but messier details.



2 On Linux, you can check your page size with the getconf command, specifying the PAGE_SIZE parameter. This returns the number of pages in bytes. 4 kilobytes (4,096 bytes) is a typical result on the x86 and x86_64 architectures, so there are 256 pages / MB.






$ getconf PAGE_SIZE
4096