关于非阻塞模式下的sendmsg()

之前的服务程序使用了多进程模式,创建一对socketpair然后主进程用sendmsg向各个工作进程分发连接fd,工作进程中所有其他的连接都是非阻塞的,但由于传递套接字的消息很小且是单向的,就简单使用了阻塞模式,也没有处理异步读写事件。

最近要主进程和工作进程之间互相传递大量数据,需要把socketpair改成非阻塞的。于是问题就是,socketpair既要传递fd又要传输大量数据,在非阻塞模式下如果缓冲区满了,那么fd还能否传递失败的话会不会丢失;再如果缓冲又有可写空间,是否得重新发送fd。总之对sendmsg函数在非阻塞模式下的行为不甚了解,网上G了一圈也没有发现有说明此类问题的文章。

于是就试一下,代码如下:

#include "msgio.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>

static int setnonblocking( int fd )
{
    int opts;

    if( fd<=0 )
        return -1;

    opts = fcntl( fd, F_GETFL );
    if( opts<0 )
        return -1;

    if( fcntl( fd, F_SETFL, opts|O_NONBLOCK ) < 0 )
        return -1;

    return 0;
}

int main()
{
    int ret;
    int ss[2];
    int pid;

    ret = socketpair( AF_UNIX, SOCK_STREAM, 0, ss );
    if( ret != 0 )
    {
        perror( "create socket pair failed" );
        return 1;
    }

    pid = fork();
    switch( pid )
    {
        case -1:
            perror( "fork failed" );
            return 2;
        case 0:
            close( ss[0] );
            setnonblocking( ss[1] );
            recver( ss[1] );
            break;
        default:
            close( ss[1] );
            setnonblocking( ss[0] );
            sender( ss[0] );
            break;
    }

    if( pid )
    {
        sleep( 2 );
        kill( pid, SIGTERM );
        wait( &ret );
    }

    return 0;
}
#include "msgio.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>

#define MSG_DATA "xyz"
#define MSG_LEN sizeof(MSG_DATA)

#define LOOP_TIMES 10000

#define print( fmt, ... ) \
    fprintf( stderr, fmt "\n", ##__VA_ARGS__ )


int sender( int fd )
{
    int ret;
    int i;
    int xfd;

    struct msghdr msghdr;
    struct iovec iov[4];
    union {
        struct cmsghdr cm;
        char data[CMSG_SPACE(sizeof(int))];
    } cmsg;

    xfd = open( "/dev/zero", O_RDONLY );
    if( xfd < 0 )
    {
        perror( "open xfd failed" );
        return -1;
    }

    cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int));
    cmsg.cm.cmsg_level = SOL_SOCKET;
    cmsg.cm.cmsg_type = SCM_RIGHTS;
    *(int*)CMSG_DATA(&(cmsg.cm)) = xfd;

    iov[0].iov_base = MSG_DATA;
    iov[0].iov_len = MSG_LEN;
    iov[1].iov_base = MSG_DATA;
    iov[1].iov_len = MSG_LEN;
    iov[2].iov_base = MSG_DATA;
    iov[2].iov_len = MSG_LEN;
    iov[3].iov_base = MSG_DATA;
    iov[3].iov_len = MSG_LEN;

    msghdr.msg_name = NULL;
    msghdr.msg_namelen = 0;
    msghdr.msg_iov = iov;
    msghdr.msg_iovlen = 4;
    msghdr.msg_control = (caddr_t)&cmsg;
    msghdr.msg_controllen = sizeof(cmsg);

    print( "to send %d", MSG_LEN );

    for( i=0; i<2; i++ )
    {
        ret = sendmsg( fd, &msghdr, MSG_DONTWAIT );
        if( ret < 0 )
        {
            perror( "sendmsg failed" );
            continue;
        }

        print( "sendmsg %5d sent %d, fd %d", i, ret, xfd );
    }

    return 0;
}


int recver( int fd )
{
    int ret;
    int i;
    unsigned char buf[10];
    int xfd;

    struct msghdr msghdr;
    struct iovec iov[1];
    union {
        struct cmsghdr cm;
        char data[CMSG_SPACE(sizeof(int))];
    } cmsg;

    iov[0].iov_base = buf;
    iov[0].iov_len = sizeof(buf);

    msghdr.msg_name = NULL;
    msghdr.msg_namelen = 0;
    msghdr.msg_iov = iov;
    msghdr.msg_iovlen = 1;
    msghdr.msg_control = (caddr_t)&cmsg;
    msghdr.msg_controllen = sizeof(cmsg);

    sleep(1);

    for( i=0; i<4; i++ )
    {
        ret = recvmsg( fd, &msghdr, 0 );
        if( ret < 0 )
        {
            perror( "recvmsg failed" );
            continue;
        }

        if( cmsg.cm.cmsg_len < CMSG_LEN(sizeof(int)) )
        {
            print( "msg control data len %u", cmsg.cm.cmsg_len );
            continue;
        }
        if( cmsg.cm.cmsg_level != SOL_SOCKET || cmsg.cm.cmsg_type != SCM_RIGHTS )
        {
            print( "msg control level %d, type %d", cmsg.cm.cmsg_level, cmsg.cm.cmsg_type );
            continue;
        }

        xfd = *(int*)CMSG_DATA( &(cmsg.cm) );
        print( "recvmsg %5d recv %d, fd %d", i, ret, xfd );
        //close( xfd );
    }

    return 0;
}

测试结果为:

to send 4
sendmsg     0 sent 16, fd 4
sendmsg     1 sent 16, fd 4
recvmsg     0 recv 10, fd 3
recvmsg     1 recv 10, fd 5
recvmsg     2 recv 10, fd 5
recvmsg     3 recv 2, fd 5

父进程分两个发送了32字节数据,每次附带一个fd。子进程分四次接收,数据接收完整,也只收到了两个fd。

特别是第二次的接收,数据中包含父进程两次消息中的数据,但fd为第二个消息的fd。随后的接收到的都是同一个fd。

由此可以猜测,fd的传递和数据类似于两个通道。由于一个进程中的fd是唯一的,子进程在收到fd后可以判断出是否是新的fd。

将recver()函数中的buf大小改为 10*MSG_LEN 进行测试,结果为:

to send 4
sendmsg     0 sent 16, fd 4
sendmsg     1 sent 16, fd 4
recvmsg     0 recv 16, fd 3
recvmsg     1 recv 16, fd 5
recvmsg failed: Resource temporarily unavailable
recvmsg failed: Resource temporarily unavailable
可见两次发送的消息没有合并,猜测内核对此进行了处理,只允许一个消息中包含一个fd。

over

使用 titlesec 宏包设置标题格式

<p>在 <a href="http://mlsx.xplore.cn/tag/xelatex" rel="tag nofollow" title="标签 xelatex 下的日志">xelatex</a> 中使用 \usepackage 指令使用 titlesec 宏包时,可以指定一些格式选项,如下:<br>\usepackage[center]{titlesec}<br>其中 center 可使标题居中,还可设为 raggedleft (居左,默认), raggedright (居右)。<br>标题由标签与标题内容构成,其格式通常在 <a href="http://mlsx.xplore.cn/tag/xelatex" rel="tag nofollow" title="标签 xelatex 下的日志">xelatex</a> 文档导言区通过 titlesec 宏包提供的指令 \titleformat 进行设定。 \titleformat 指令用法如下:<br>\titleformat{command}[shape]{format}{label}{sep}{before}[after]<br>各参数含义如下:<br><span></span><br>command 是要重新定义的各种标题命令,比如 \part,\chapter,\section,\subsection,\subsubsection,\paragraph,\subparagraph等;<br>shape 是用来设定段落形状的,可选的参数有 hang 、 block 、 display 等,详见 titlesec 文档,位于: <br>$TEXLIVE/$VERSION/texmf-dist/doc/<a href="http://mlsx.xplore.cn/tag/latex" rel="tag nofollow" title="标签 latex 下的日志">latex</a>/titlesec<br>format 用于定义标题外观,比如使标题居中、字体加粗等;<br>label 用于定义定义标题的标签,就是标题内容前面的标号;<br>sep 定义标题的标签与标题内容之间的间隔距离。<br>before 用于在标题内容前再加些内容;<br>after 用于在标题内容后再加些内容。<br>这个指令看似很复杂,但在实际应用中,通常只使用它的几个参数而已。比如,要把文档中的章标题格式由默认的 “Chapter xxx 标题内容” 修改为 “第 xxx 章 标题内容” 格式,如此这般即可:<br>\titleformat{\chapter}{\centering\Huge\bfseries}{第\,\thechapter\,章}{1em}{}<br>其 中, shape 、 before 、 after 参 数 都 被 省 略 掉 了。 format 参 数 将章标题设置为居中( \centering )显示、字号为 \Huge,字体被加粗显示 \bfseries ;在设置 subsection 格式,未采用居中,而是采用默认的居左,另外将标题的字号也降了一级( \large )。 label 参数将标题的标签设置为 “第 xxx 章”格式。 sep 参数设置标签与标题内容之间以一个字(1em)的宽度为间隔。以上设置的章标题效果如下图所示:<br><img style="width:245px;height:76px" src="http://www.google.com/base_media?hl=en&amp;fact=12e&amp;size=3&amp;q=http://www.is-programmer.com/user_files/lyanry/Image/latex-chapter-title1.png&amp;dhm=29ca03fe"><br>如果为上面设置章标题的命令添加一个 shape 参数 “display”,如下:<br>\titleformat{\chapter}[display]{\Huge\bfseries}{第\,\thechapter\,章}{1em}{}<br>这样设置后的章标题效果如下图所示。<br><img style="width:245px;height:94px" src="http://www.google.com/base_media?hl=en&amp;fact=12e&amp;size=3&amp;q=http://www.is-programmer.com/user_files/lyanry/Image/latex-chapter-title2.png&amp;dhm=f66ff448"><br>只要弄明白了 \titleformat 用法,基本上可以实现 <a href="http://mlsx.xplore.cn/tag/xelatex" rel="tag nofollow" title="标签 xelatex 下的日志">xelatex</a> 排版时将文档的章节标题修改为符合中文阅读习惯的格式。<br>使用 fancyhdr 设置页眉页脚<br>在 <a href="http://mlsx.xplore.cn/tag/xelatex" rel="tag nofollow" title="标签 xelatex 下的日志">xelatex</a> 文档导言区使用以下指令可载入宏包 fancyhdr,并将页眉页脚风格设置为 fancy:<br>\usepackage{fancyhdr}<br> \pagestyle{fancy}<br>fancyhdr 宏包将页面分为奇数页(Odd page)和偶数页(Even page),将页眉与页脚各分为三个区域,分别称为左区(Left field)、中区(Center field)和右区(Right field)。这三个区域之间没有分界线,左区中的内容会左对齐在页眉或页脚的左边界,放在右区的内容会对齐在页眉或页脚的右边界,中区内容在整个页眉或页脚区域内居中放置。各区之中的内容不可过长,以避免各区之间发生重叠现象。另外,在默认情况下会显示页眉线,宽度为 0.4pt;页脚线宽都为 0pt,意即不显示。<br>设置页眉的命令为 \fancyhead,设置页脚的命令为 \fancyfoot,其用法如下:<br>\fancyhead[选项参数] {内容}<br> \fancyfoot[选项参数] {内容}<br>\fancyhead 的选项参数页眉或页脚的区域与奇(偶)数页标记的组合,其中页眉(脚)区域用 L (左),C (中),R( 右) 表示,奇数页与偶数页分别用字母 O,E 表示。<br>下面来做一个例子,对于 book 格式的 <a href="http://mlsx.xplore.cn/tag/xelatex" rel="tag nofollow" title="标签 xelatex 下的日志">xelatex</a> 文档,让偶数右区域显示章标题,其左区域显示页码,中间区域为空;让奇数页的页眉左区域显示节标题,其右区域显示页码,其中间区域为空;页脚为空。这个可以在文档导言区中采用以下指令实现:<br> </p><div><ol title="Double click to hide line number."><li>&amp;#92;renewcommand{&amp;#92;chaptermark}&amp;#91;1&amp;#93;{&amp;#92;markboth{&amp;#92;small 第&amp;#92;,&amp;#92;thechapter&amp;#92;,章&amp;#92;quad #1}{}}</li> <li> &amp;#92;renewcommand{&amp;#92;sectionmark}&amp;#91;1&amp;#93;{&amp;#92;markright{&amp;#92;small&amp;#92;thesection&amp;#92;quad #1}{}}</li> <li> </li> <li> &amp;#92;fancyhf{}</li> <li> &amp;#92;fancyhead&amp;#91;ER&amp;#93;{&amp;#92;leftmark}</li> <li> &amp;#92;fancyhead&amp;#91;OL&amp;#93;{&amp;#92;rightmark}</li> <li> &amp;#92;fancyhead&amp;#91;EL,OR&amp;#93;{$&amp;#92;cdot$&amp;#92; &amp;#92;thepage&amp;#92; $&amp;#92;cdot$}</li> <li> &amp;#92;renewcommand{&amp;#92;headrulewidth}{0.4pt}</li></ol></div> <p><br>\fancyhf{} 命令可将已设或页眉页脚的默认设置清空。<br>重新定义了 \chaptermark 与 \sectionmark,这两个重定义一定要记住放在 \pagestyle{fancy}之后,因为在 fancyhdr 宏包中对这两个命令重新进行了定义,在 \pagestyle{fancy} 之后重定义它们就可将 fancyhdr 中的相应命令覆盖掉。<br>还需要解释的是 \leftmark 与 \rightmark,它们分别表示页眉左区域内容与右区域内容。在 book 格式文档中,\leftmark 默认为当前的章标题,\rightmakr 默认为当前的节标题;对于 article 格式文档而言,\leftmark 表示当前节标题,\rightmark 表示当前小节标题。<br>okay,现在看看输出的文档,是不是稍微专业了一些?</p>

阅读全文

SHELL彩色的命令行

<table><tbody><tr><td align="center" height="25"><br></td> </tr> <tr> <td align="center" height="9"><img style="width:245px;height:4px" alt="" src="http://blog.chinaunix.net/templates/default/images/right_line.gif" border="0" height="9" width="502"></td> </tr> <tr> <td align="center"> <table style="border-collapse:collapse" border="0" cellpadding="0" cellspacing="0" width="740"> <tbody> <tr> <td width="740"> <div style="margin:15px" width="560"> <table style="border-collapse:collapse" bgcolor="#ffffff" border="0" cellpadding="0" cellspacing="0" width="760"> <tbody> <tr> <td align="center" height="25"><font style="font-size:14pt" color="#02368d"><b>彩色的命令行</b></font><br></td> </tr> <tr> <td align="center" height="9"><br></td> </tr> <tr> <td align="center"> <table style="border-collapse:collapse" border="0" cellpadding="0" cellspacing="0" width="740"> <tbody> <tr> <td width="740"> <div style="margin:15px;line-height:150%" width="560"> <div><span> <h2>概述</h2> 本文以 Bash shell 为例。(不同的终端里的转义序列不完全相同). <h2>Shell 的配置</h2> shell 彩色配置出现在 bash 的个人配置文件 <i>~/.bashrc</i> 或者是全局配置文件 <i>/etc/bashrc</i> 里面。 可以通过 <i>bashrc</i> 里面的 PS1 变量来设置提示符的外观。 <br><br>例如: <table> <tbody> <tr> <td> <pre>PS1=&quot;\s-\v\$ &quot;</pre> <pre>\s 表示 shell 的名称,-\v 表示版本号。 在提示符的最后面放置了一个 $。</pre> <pre>PS1=&quot;\u@\h \w \$ &quot;</pre> </td> </tr> </tbody> </table> 表示 用户@ 当前目录 $ <h2>转义序列</h2> 要是通过彩色化提示符来增加个性化,就要用到转义序列。 转义序列就是一个让 shell 执行一个特殊步骤的控制指令。转义序列通常都是以 ESC 开头(这也是它的命名原因)。 在 shell 里表示为 ^[。也可以用 \033 完成相同的工作(ESC 的 ASCII 码用十进制表示就是 27,  用八进制表示为 33)。<br><br>要直接在 shell 里面输入转义序列需要先按 ctrl-v:<i>CTRL-v ESC</i>。 <a name="335lfindex3"> </a> <h2>使用 shell 的颜色</h2> 下面用一个提示符的例子来解释 shell 的颜色。 <pre>PS1=&quot;\[\033[0;32;40m\u@\h:\w\$ \]&quot;</pre> <pre>这样提示符就全部显示成绿色了。就像这样:<br></pre> <center> <table border="0" cellpadding="10"> <tbody> <tr> <td bgcolor="#000000"><font color="#00ff00">nico@ebrain:~$</font> </td> </tr> </tbody> </table> </center> <p><br>\033 声明了转义序列的开始,然后是 [ 开始定义颜色。 后面的 0 定义了默认的字体宽度。稍后我会介绍其他的可用字符。 转义序列字符串要用 \[ 和 \] 括起来, 防止转义序列的文本显示在 shell 里占用太多的空间。<br><br>下面要选择前景色(这里是 32,代表绿色)。背景色的 40 表示黑色。 要是不想让提示符后面的文字也变成绿色,需要用 \033[0m 关闭转义序列, \033[0m 是 shell 的默认颜色。前景色和背景色都有 8 种可用的选择。<br><br>可选颜色:红色、绿色、黄色、蓝色、洋红、青色和白色。 他们对应的颜色代码是:30(黑色)、31(红色)、32(绿色)、 33(黄色)、34(蓝色)、35(洋红)、36(青色)、37(白色)。<br><br>用同样色方法设置背景色,不过要把第一个数字“3”替换成“4”, 例如 40、41、42、43、44、45、46、47。<br><br>示例: </p> <pre>PS1=&quot;\[\033[0;37;44m\u@\033[0;32;43m\h:\033[0;33;41m\w$\033[0m\]&quot;<br>这给了非常多彩的提示符:<br></pre> <center> <table border="0" cellpadding="10"> <tbody> <tr> <td bgcolor="#000000"> <table border="0" cellpadding="0" cellspacing="0"> <tbody> <tr> <td bgcolor="#0000ff"><font color="#ffffff">nico@</font></td> <td bgcolor="#aa5500"><font color="#00ff00">ebrain:</font></td> <td bgcolor="#ff3030"><font color="#aa5500">~$</font></td> </tr> </tbody> </table> </td> </tr> </tbody> </table> </center><br>使用 <i>export PS1=&quot;string&quot;</i> 来测试这些设置; <pre>PS1=&quot;\[\033[1;34;40m[\033[1;31;40m\u@\h:\w\033[1;34;40m]\033[1;37;40m $\033[0;37;0m\] &quot;<br></pre> <br><center> <table border="0" cellpadding="10"> <tbody> <tr> <td bgcolor="#000000"><b><font color="#0000ff">[</font> <font color="#0000ff">nico@ebrain:~</font> <font color="#0000ff">]</font></b> </td> </tr> </tbody> </table> </center><a name="335lfindex4"> </a> <h2>文本属性</h2> <p>刚才提到了,在第一个转义序列后面的“0”是提示符的文本的默认颜色设置。 对于文本属性来说,有意义的值及对应关系为:<br>0、默认值<br>1、粗体<br>22、非粗体<br>4、下划线<br>24、非下划线<br>5、闪烁<br>25、非闪烁<br>7、反显<br>27、非反显</p> <p>通过下面这一段短小的脚本,可以看看色彩组合。 </p> <pre>#!/bin/sh<br>############################################################<br># Nico Golde &lt;nico(at)<a href="http://ngolde.de">ngolde.de</a>&gt; Homepage: <a href="http://www.ngolde.de">http://www.ngolde.de</a><br># Last change: Mon Feb 16 16:24:41 CET 2004<br>############################################################<br><br>for attr in 0 1 4 5 7 ; do<br> echo &quot;----------------------------------------------------------------&quot;<br> printf &quot;ESC[%s;Foreground;Background - \n&quot; $attr<br> for fore in 30 31 32 33 34 35 36 37; do<br> for back in 40 41 42 43 44 45 46 47; do<br> printf &#39;\033[%s;%s;%sm s;s &#39; $attr $fore $back $fore $back<br> done<br> printf &#39;\n&#39;<br> done<br> printf &#39;\033[0m&#39;<br>done<br></pre> <h2>另一个程序</h2> 在 shell 中设置颜色不仅仅能创建更加漂亮的提示符, 在编写控制台程序的时候也非常有用。<br><br>对于一个要使用彩色的程序员,就必须要使用类似 <i>slang</i> 或 <i>ncurses</i> 这样的的库,者通常会增加执行文件的大小。 <i>Ncurses</i> 有着或多或少的独立于终端的类型的优势。 <a name="335lfindex6"> </a> <h2>C 语言示例</h2> 用绿色打印“Hello Word”: <pre>#i nclude &lt;stdio.h&gt;<br>int main(void){<br> const char *const green = &quot;\033[0;40;32m&quot;;<br> const char *const normal = &quot;\033[0m&quot;;<br> printf(&quot;%sHello World%s\n&quot;, green, normal);<br> return 0;<br>}<br></pre> 另外一个有用的转义序列是 <i>printf(&quot;\033[2J&quot;)</i>,它和 <i>system(clear)</i> 完成的功能一样。但是可以不需要头文件 <i>unistd.h</i>。<br><br>使用<i>printf(&quot;\033[1K&quot;)</i> 可以删除一行。 <a name="335lfindex7"> </a> <h2>初始化脚本示例</h2> 如果想在 <i>/etc/init.d</i> 的 <i>init</i> 脚本成功的执行后, 得到一个漂亮的、清晰易读的提示,而不是一个简单的 <i>&#39;.&#39;</i>, 可以再一次的使用转义序列。<br><br>这是一段 <i>cron init script</i> 的摘录: <pre>#!/bin/sh<br># Start/stop the cron daemon.<br>test -f /usr/sbin/cron || exit 0<br><br> case &quot;$1&quot; in<br> start) echo -n &quot;Starting periodic command scheduler: cron&quot;<br> start-stop-daemon --start --quiet --exec /usr/sbin/cron<br><br> echo &quot;.&quot;<br>;;<br><br></pre> 如果 <i>cron</i> 脚本执行成功就会显示一个句点。 可以用 [Ok] 给这些信息添加上彩色特征,通过改变 <i>echo</i> 字符串,例如: <pre>#!/bin/sh<br># Start/stop the cron daemon.<br>test -f /usr/sbin/cron || exit 0<br>case &quot;$1&quot; in<br>start) echo -n &quot;Starting periodic command scheduler: cron&quot;<br> start-stop-daemon --start --quiet --exec /usr/sbin/cron<br>echo &quot;\[ \033[1;34;40m[ \033[1;32;40mOk \033[1;34;40m]\033[0m\]&quot;<br> ;;<br></pre> <p>把这个设置应用到所有的 <i>init</i>脚本上非常耗费时间, 除非使用转义序列 \033 —— 因为 <i>Ctrl-v</i> 不是作为一个字符来处理的。 <a name="335lfindex8"> </a></p> <p> </p> <p><b>定制命令提示符</b></p> <p>我们可以定制要显示的bash命令提示符,包括当前用户名和主机名,当前时间,平均负载和当前工作目录。要实现该目的,修改$PS1变量,如下所示:</p> <p>bash&gt; PS1=&#39;u@h:w @&gt; &#39;<br>bash&gt; export PS1<br>root@medusa:/tmp 03:01 PM&gt;</p> <p>结果将会在命令行显示当前登录的用户名、主机名、当前工作目录和当前时间。从用户指南页可以获得bash可以理解的符号列表。</p> </span></div> </div></td></tr></tbody></table></td></tr></tbody></table></div></td></tr></tbody></table></td></tr></tbody></table>

阅读全文

Beamer学习笔记

<p>这次的演讲全部用<a href="http://latex-beamer.sf.net">Beamer</a>重做,除主文件,样式文件外,根据演讲的主题的不同,分成了好几个文件,编译成PDF后,一共128页,没有什么炫的技术,但是相比以前花了N多心思做的PPT,看上去要专业很多。现在基本上能用<a href="http://mlsx.xplore.cn/tag/beamer" rel="tag nofollow" title="标签 beamer 下的日志">Beamer</a>做出我需要的简报了,也有一些学习的记录,贴出来和大家共享。</p> <p>使用<a href="http://mlsx.xplore.cn/tag/beamer" rel="tag nofollow" title="标签 beamer 下的日志">Beamer</a>,首先需要申明文档类型为<a href="http://mlsx.xplore.cn/tag/beamer" rel="tag nofollow" title="标签 beamer 下的日志">beamer</a>,最简单的当然是<br> documentclass{<a href="http://mlsx.xplore.cn/tag/beamer" rel="tag nofollow" title="标签 beamer 下的日志">beamer</a>}</p> <p>不过这样子的话,基本你编译不出PDF,即便能编译出来,那查看PDF时,也会报错。<br> <span></span><br> 它带来大量的可选参数,有些其实是必须的,特别是在中文环境下,我这里不再使用LaTeX-CJK宏,而是直接采取<a href="http://mlsx.xplore.cn/tag/xetex" rel="tag nofollow" title="标签 xetex 下的日志">XeTeX</a>方式编译,因此下面所讲,均是针对<a href="http://mlsx.xplore.cn/tag/xetex" rel="tag nofollow" title="标签 xetex 下的日志">XeTeX</a>-LaTeX环境编译的。</p> <p>我目前学到的参数有下面这些<br> documentclass[dvipdfm,dvipsnames,xcolor=pdflatex,table,handout,draft,red,compress]{<a href="http://mlsx.xplore.cn/tag/beamer" rel="tag nofollow" title="标签 beamer 下的日志">beamer</a>}<br> %dvipdfm是关键,否则要么编译通不过,要不生成的pdf无法打开<br> %xcolor=pdflatex选项使得xcolor宏包可以使用,表示xcolor的颜色驱动选择<br> %dvipsnames表示可以使用预定义的颜色名字,比如RoyaBlue<br> %table是告诉xcolor宏包colortbl宏包需要加载<br> %xcolor会自动加载,不需要手工显式调用<br> %handout 处理传单形式,加上这个参数后,overlay,也就是动画效果会去掉,比如你逐项显式的内容,会在一个PDF页面上显示。<br> %draft 草稿模式,在撰写的过程中,可以加入这个参数,主要加快编译速度,不过在我使用的过程,也发现了一些问题。因为draft模式会省去头,尾和侧边栏,所以 填写的地方显得大一些,当你按照这个宽度和高度撰写内容后,再去掉draft编译,就会发现很多内容看不到了,因为显示内容的面积变小了。<br> %red显示指定页面头,尾或侧边栏的颜色<br> %compress尽量压缩侧边栏</p> <p>接下来设定简报的风格,我用到了三个命令<br> usepackage{beamerthemesplit}<br> usetheme{Berkeley}<br> usecolortheme{dolphin}</p> <p>这些主题和颜色,你可以从$TEXMF/tex/latex/<a href="http://mlsx.xplore.cn/tag/beamer" rel="tag nofollow" title="标签 beamer 下的日志">beamer</a>/下找到,自带的主题还是比较多,不过我没有一一查看到底每一个主题是什么样子。</p> <p>接着调用fontspec包,这是<a href="http://mlsx.xplore.cn/tag/xetex" rel="tag nofollow" title="标签 xetex 下的日志">XeTeX</a>所必须的,用来设定你需要的字体<br> usepackage{fontspec}</p> <p>下载你可以设置字体了,<a href="http://mlsx.xplore.cn/tag/beamer" rel="tag nofollow" title="标签 beamer 下的日志">Beamer</a>默认使用Sans family字体,因此你至少需要设定Sans family字体,我一般使用下面的命令:<br> setsansfont{SimSun}<br> 当然你还可以设定一些其他字体,比如罗马字体<br> setromanfont{Times New Roman}</p> <p>从别的地方还看到有下面的字体设置方法,不过我很少使用<br> %设置字体时也可以直接用字体名,以下三种方式等同:<br> %setromanfont[BoldFont={黑体}]{宋体}<br> %setromanfont[BoldFont={SimHei}]{SimSun}<br> % setromanfont[BoldFont={&quot;[simhei.ttf]“}]{”[simsun.ttc]“}</p> <p>如果是撰写中文简报,还需要下面两行命令:<br> XeTeXlinebreaklocale “zh”  % 表示用中文的断行<br> XeTeXlinebreakskip = 0pt plus 1pt % 多一点调整的空间</p> <p>如果没有这两行,编译出来的PDF会很丑,当然这其实和<a href="http://mlsx.xplore.cn/tag/beamer" rel="tag nofollow" title="标签 beamer 下的日志">Beamer</a>无关,是<a href="http://mlsx.xplore.cn/tag/xetex" rel="tag nofollow" title="标签 xetex 下的日志">XeTeX</a>的问题,只要使用<a href="http://mlsx.xplore.cn/tag/xetex" rel="tag nofollow" title="标签 xetex 下的日志">XeTeX</a>,不管是用哪种文档样式,只要涉及到中文,均需要使用上面两行命令。</p> <p>现在可以开始撰写简报,首先使用我们熟悉的 itle,author,date定义必要的信息。然后针对每一个幻灯片,<a href="http://mlsx.xplore.cn/tag/beamer" rel="tag nofollow" title="标签 beamer 下的日志">Beamer</a>使用<br> egin{frame}<br> end{frame}<br> 来定义,几种绝大部分LaTeX的命令都可以使用。</p> <p>当然egin{frame}也可以带一些参数,我仅列出我使用到的</p> <p>egin{frame}[shrink=5]</p> <p>当frame的内容不能在单个frame下存放时,就会把文字大小缩至少指定数的百分比,不建议使用这个参数。</p> <p>egin{frame}[&lt; -&gt;]</p> <p>[&lt; -&gt;]会自动逐条显示内容,而不需要使用&lt;1-&gt;,&lt;2-&gt;这样的流水</p> <p>egin{frame}[fragile] / egin[containsverbatim]{frame}<br> 在<a href="http://mlsx.xplore.cn/tag/beamer" rel="tag nofollow" title="标签 beamer 下的日志">Beamer</a>文档样式下,verbatim环境不能直接使用,需要用到上面两个参数之间的一个,为了找到这个参数,花了不少时间。</p> <p>上面的情况,虽然可以使用verbatim环境了,但是如果在verbatim里使用中文还是看不到,需要使用到下面的命令:<br> makeatletter<br> defverbatim@font{sffamily} %如果使用roman字体族,将sffamily改成rmfamily<br> makeatother</p> <p>egin{frame}[allowframebreaks,allowdisplaybreaks]<br> 当一个frame过长时,会自动打破为成为多个frame,这个参数绝对有用,这个参数也花了我不少时间找到它。</p> <p>上面这些是不太容易从<a href="http://mlsx.xplore.cn/tag/beamer" rel="tag nofollow" title="标签 beamer 下的日志">Beamer</a>的手册中找到,所以列了出来,其他的一些功能,比如怎么设置动态效果呀,怎么插入图片呀,都从手册上能找到,而且也和LaTeX基本相同。</p> <p>另外,我在使用<a href="http://mlsx.xplore.cn/tag/beamer" rel="tag nofollow" title="标签 beamer 下的日志">Beamer</a>的过程中,还简单学会了用<a href="http://sourceforge.net/projects/pgf/">TiKZ</a>画图,比如我要解释Linux文件系统布局图,类似下面这样:</p> <p><img style="width:0px;height:12px" src="http://www.google.com/base_media?hl=en&amp;fact=12e&amp;size=3&amp;q=http://mlsx.xplore.cn/wp-content/uploads/200803/1206793358_4738f742.png&amp;dhm=d990db37" alt=""><br> 就可以使用下面的命令:</p> <div><div><pre style="font-family:monospace">egin<span>{</span><span style="color:rgb(34, 34, 208);font-weight:normal">tikzpicture</span><span>}</span><span>[</span><span style="color:rgb(34, 34, 208);font-weight:normal">auto,thick</span><span>]</span> ikzstyle<span>{</span><span style="color:rgb(34, 34, 208);font-weight:normal">node</span><span>}</span>=<span style="color:rgb(128, 128, 128);font-style:italic">%</span> <span>[</span><span style="color:rgb(128, 128, 128);font-style:italic">%</span> minimum size=10pt,<span style="color:rgb(128, 128, 128);font-style:italic">%</span> inner sep=0pt,<span style="color:rgb(128, 128, 128);font-style:italic">%</span> outer sep=0pt,<span style="color:rgb(128, 128, 128);font-style:italic">%</span> <span style="color:rgb(128, 128, 128);font-style:italic">

阅读全文

用 LaTeX 写漂亮学位论文

原文:ymei.freeshell.org/WebWiki/Computer/ThesisWithLaTeX.html

一直觉得有必要写这样一篇文章,因为学位论文从格式上说更像一本书,与文章 的排版不同,不仅多出目录等文章没有的部分,而且一般要设置页眉页脚方便阅 读查找。学校有时会提出具体的格式要求,虽然复旦的要求非常简单,而且事实 上并不严格执行,但自己的论文毕竟是自己的孩子,还是要敝帚自珍的,大家都 希望做得漂亮一点。

网上已经有不少学位论文的模板,其中大都出自一两个最初的版本,针对各自学 校的要求作了一些改动。这些模板还是很方便的,如果对它们的排版效果感到完 全满意,那么直接拿来用就可以了。不过如果想调整其中某些格式,就不得不仔 细研究一下它们的代码或说明文档,有时并不那么容易。而且这些模板的导言或 cls或sty文件都写得很长,内容很多,尽可能的包含了大家有可能用到的功能, 但其实具体到每个人只有一部分是需要用到的。用一个包含“冗余”代码的模板, 总不是一件很舒服的事情。当然也许很多人抱着能用就好的态度,并不care。:)

本文是为那些对论文格式有特殊要求或喜欢自己设置格式的人写的。如果你觉得 网上能找到的论文模板已经足以满足你的需要,并且对TeX本身也没有多少兴趣, 那么你没有必要花费宝贵的时间阅读本文。

阅读本文的基础是假定你已经了解怎样用LaTeX来写普通的文章。一般的 TeX/LaTeX命令不会再作解释,重点将放在学位论文与普通文章的不同点上,以及 怎样用一些宏包方便地设置其格式。其中大部分内容来源于网络资源、工具书以 及各个宏包的说明文档,恕不一一注明,在此一并致谢!

首先讲一下纸张大小和页边距的设置。根据复旦的格式要求,纸张大小为A4纸, 正文用小四号字,页边距按Word中的默认设置。小四号字即12pt, Word中默认的 页边距为

上边距=2.54cm, 下边距=2.54cm, 左边距=3.17cm, 右边距=3.17cm

或者换算成更容易记忆的

上边距=1in, 下边距=1in, 左边距=1.25in, 右边距=1.25in

如果我们用book类,第一句可以写

\documentclass[a4paper,12pt]{book}

然后用geometry宏包设置页边距

\usepackage[top=1in,bottom=1in,left=1.25in,right=1.25in]{geometry}

但其实这样设置的页边距极不美观,尤其是左右对称的页边距没有考虑装订的需 要,而且加上页眉后这样的上边距就显得过窄。所以注重美观的话还是自己调整 一下吧。

需要注意的是,book类默认是twoside即双面打印模式,与article类默认的 oneside即单面打印模式不同。两者区别在于页边距和页码的位置。单面模式每页 的页边距都相同,双面模式则会在偶数页将设置的左、右页边距调换。如果采用 单面打印,则可在\documentclass的方括号里加上oneside参数,并在geometry的 选项中适当增加左边距,减少右边距,以留出装订线的位置。但是不要忘了装订 的时候右侧一般会裁掉一点边,所以左、右边距也不要相差过大。如果采用双面 打印,则geometry中的设置被解释为奇数页的页边距,偶数页的左、右边距会自 动互换。

还有几个注意事项。首先,这里的奇数页和偶数页是针对当前page计数器的值来 说的,而不是在生成文件中总的页码。也就是说,假如当前页在整个输出中总排 序是偶数页,但当前page计数器(即显示的页码)为奇数,则当前页的页边距是按 奇数页设置的。

其次,\documentclass还有一对选项openright和openany, book类默认是前者, 即每一章(包括目录)都会在奇数页开始,如果前一章的最后一页是奇数页,则会 在其后插入一页空白页,以确保新的一章仍然从奇数页开始。这是书籍的排版规 范,不建议改变,论文页数比较少的还可以借此增加页数。:)这是双面模式的情 况,在单面模式下不存在这个问题。经常有人问为什么自己明明是单面打印,却 仍然会在两章之间有一页空白页,请注意book类默认是双面模式,除非你设为 oneside, 记住告诉TeX你要的是什么!

另外,为了方便查看,页码应该放在书籍的外侧。对于单面模式,外侧就是右 侧,而对于双面模式,奇数页右侧是外侧,偶数页左侧是外侧。如何设置页码留 到后面讲设置页眉、页脚时再详细说。

至于到底是单面打印还是双面打印,看你自己的喜好了。复旦的论文规范没说, 一般的做法是博士双面、硕士单面。反正总页数少于50页的话,就不要双面了, 否则显得太单薄,书脊的内容都很难打印。

最后提一个常见的问题。如果用pdf文件来打印,在Acrobat的打印对话框里有一 项Page Scaling默认是Fit to paper, 这样打印出来整个内容就会缩小一些,不 再是设置的尺寸。这是因为打印机的可打印范围不能达到整个A4纸张的全部,而 是比A4纸的规格要小一些(具体的可打印范围跟打印机型号有关), Fit to paper 的意思就是把整个页面调整到可打印范围上去,以保证所有页面上的内容都能打 印出来。因为可打印范围总是小于A4纸的尺寸,所以打印出来总是会缩小一些。 缩小的比例一般为95%左右,与打印机型号有关。解决这个问题,只要选择Page Scaling为None就可以了。

这一节讲中文字体和中英文混排的问题。中文处理推荐使用CJK或新版CCT, 旧版 CCT因为年代久远,有一些bug会导致莫名其妙的问题,不建议再使用。本文以 CJK为例,中文环境为

\begin{CJK*}{GBK}{song}
...
\end{CJK*}

与英文习惯不同,中文排版一般没有粗体的概念,而是用宋体、黑体、楷体、仿 宋等不同的字体来加强文本效果。在CJK默认的字体定义文件中,宋体对应的粗体 是用\CJKbold 命令通过微小平移字形来实现的,不仅放大后能看到锯齿,而且也 不符合中文的排版习惯。建议将宋体对应的粗体设为黑体,这样文中所有粗体命 令作用的环境中加粗的宋体都会自动变成黑体,不需要再用\CJKfamily{hei}来转 换。

宋体的字体定义文件C19song.fd里典型的一段代码如下

\DeclareFontFamily{C19}{song}{}
\DeclareFontShape{C19}{song}{m}{n}{<-> CJK * gbksong}{}
\DeclareFontShape{C19}{song}{bx}{n}{<-> CJKb * gbksong}{\CJKbold}
\DeclareFontShape{C19}{song}{m}{it}{<-> CJK * gbksongsl}{}
\DeclareFontShape{C19}{song}{bx}{it}{<-> CJKb * gbksongsl}{\CJKbold}
\DeclareFontShape{C19}{song}{m}{sl}{<-> CJK * gbksongsl}{}
\DeclareFontShape{C19}{song}{bx}{sl}{<-> CJKb * gbksongsl}{\CJKbold}

这里C19代表GBK字符集的编码方式,m表示字符的粗细程度和宽紧程度均为中等 (medium), bx表示字符的属性为粗(bold)和松(expanded), n, it和sl分别表示正 常直立体(normal), 意大利斜体(italic)和机械斜体(slanted)。 \DeclareFontShape的最后两个参数分别是字体定义和命令序列。显然,上述语句 将宋体的粗体定义为用\CJKbold 生成。要将其改为黑体,只需将这段代码改为

\DeclareFontFamily{C19}{song}{}
\DeclareFontShape{C19}{song}{m}{n}{<-> CJK * gbksong}{}
\DeclareFontShape{C19}{song}{bx}{n}{<-> CJKb * gbkhei}{}
\DeclareFontShape{C19}{song}{m}{it}{<-> CJK * gbksongsl}{}
\DeclareFontShape{C19}{song}{bx}{it}{<-> CJKb * gbkheisl}{}
\DeclareFontShape{C19}{song}{m}{sl}{<-> CJK * gbksongsl}{}
\DeclareFontShape{C19}{song}{bx}{sl}{<-> CJKb * gbkheisl}{}

实际上,正式的中文排版也不应使用斜体,而应使用楷体或仿宋代替。所以也可 以类似地将上述语句中的gbksongsl改为gbkkai或gbkfs。

上述字体定义命令可以放在sty文件中(设保存文件名为thesis.sty, 则在导言区 用\usepackage{thesis}引用,后面所述的大部分命令也都可以放在sty文件中), 而不需要更改本地机器上的fd文件,以便在别的机器上也能产生同样的效果。

另外,为了方便可以定义几个简短的字体转换命令

\newcommand{\song}{\CJKfamily{song}}
\newcommand{\hei}{\CJKfamily{hei}}
\newcommand{\kai}{\CJKfamily{kai}}
\newcommand{\fs}{\CJKfamily{fs}}

以后就可以用\song, \hei, \kai和\fs在文中转换字体了。

在用\begin{CJK*}{GBK}{song}开始中文环境后,应加上\CJKindent和\CJKtilde 两句。前者将段首缩进设为两个中文字符的宽度。后者则是为了解决中英文混排 的美观问题。CJK*环境会吞掉跟在汉字后面的空格,从而使得源文件中的换行不 会在相邻汉字之间产生空白。但是这样一来,像下面这样输入的中英文内容

中文 abc 中文

就会产生如下效果

中文abc 中文

即abc两侧的空白不一样,很不美观。为解决这个问题,\CJKtilde重新定义了波 浪符~的意义,使得这个符号不再代表一个不可断行的空格,而是一个可断行的弹 性距离,加在中文和英文之间调整它们的距离。上面的中英文内容应该这样输入

中文~abc~中文

就能得到良好的效果。这个输入方式最好一开始就形成习惯,否则后来再加会很 麻烦。当然你也可以这样输入

中文abc中文

这样的话虽然中英文之间的距离太窄,但至少左右对称,比上述第一种方式略 好,是偷懒的办法。不过如果你比较在意排版质量的话,还是忍受一下输入~的麻 烦吧。

中英文混排有一些标点的问题要处理好。首先是在默认的CJK环境里,行末的中文 标点不能与边界对齐,因为中文标点也被视为一个普通的全角字符,所以看起来 行末就有了不应该有的空白,这不符合中文的排版习惯。另外,当一行文字需要 压缩或拉伸时,逗号与句号也应该区别对待,逗号后面留的空白应该比句号小一 些。这两个问题用CJKpunct 宏包就能很好地解决,只要加上 \usepackage{CJKpunct}即可。

此外,中英文混排的时候是用中文标点还是英文标点呢?这并没有统一的规范。 不过比较合理也比较通行的做法是,中文后用中文标点,英文后用英文标点。比 较特殊的两个标点是句号和括号。一般数学文章习惯用全角的实心句点作为中文 句号,这样看起来与英文的句号比较一致。全角的中文括号看起来不太好看,可 以统一使用英文的括号,不过左括号前面和右括号后面最好加上波浪符~以和前后 的文字留出适当的距离。

上面说的这几点也许比较琐碎,不过也正是最能看出是否精心排版的地方。

下面几节讲怎样用titlesec和titletoc宏包设置章节标题、页眉页脚和目录的格 式。设置页眉页脚有一个很有名的宏包fancyhdr也可以用,不过titlesec提供的 页面设计命令更方便与它的章节标题命令配合,功能更强大。这一节先讲章节标 题格式的设置。

在引用titlesec宏包时就可以指定几个格式选项,例如

\usepackage[bf,small,center,indentafter,pagestyles]{titlesec}

其中bf设置章节标题的字体为黑体,这也是默认值,可以略去。此外,还可以设 为rm(罗马体), sf(无衬线体), tt(打字机体), md(中等黑度), up(直立体), it(意大利斜体), sl(机械斜体), sc(小体大写字母)。

small设置标题字体的尺寸,还可设为big(默认), medium, tiny。

center使标题居中,还可以设为raggedleft(居左,默认), raggedright(居右)。

indentafter相当于宏包indentfirst的作用,使标题下面的第一个段落正常缩进。

pagestyles是申明后面要自定义页面样式。

下面就可以用\titleformat, \titlespacing, \titlelabel等命令来设置标题格 式了。因为这些命令里会用到中文,所以要在设置之前放一个空的CJK环境,如

\begin{CJK*}{GBK}{song}
\end{CJK*}

下面的\titleformat命令设置了章标题的格式

\titleformat{\chapter}[hang]{\centering\LARGE\bfseries}{\chaptername}{1em}{}

其中\chapter可以换为\section, \subsection等,设置节、小节等标题的格式。

hang表示标题头与标题内容在同一行,是默认值。而book类默认的章标题是标题 头与标题内容放在两个段落,对应于display选项。此外还有block, runin, leftmargin, rightmargin, frame, wrap等选项,一般不大用到。

\centering\LARGE\bfseries这一块是设置标题的排版格式,这里设置为居中、 \LARGE尺寸和黑体。

后面紧跟的是标题头的定义。book类里的标题头是英文,需要改成中文。如果希 望改成“第一章”这样的格式,则应先引用CJKnumb宏包,它提供了把阿拉伯数字转 换成中文数字的命令。然后定义

\renewcommand{\chaptername}{第\CJKnumber{\thechapter}章}

那么\titleformat里的标题头定义\chaptername就得到我们希望的效果。当然你 也可以不用中文数字而用阿拉伯数字,即定义

\renewcommand{\chaptername}{第~\thechapter~章}

跟在标题头定义后面的是标题头与标题内容之间的距离,这里是1em。注意,在中 文环境里1em等于一个汉字的宽度。

最后一个花括号内是在排版标题前执行的命令,这里空置。

然后用\titlespacing或\titlespacing*命令设置标题与四周的距离,例如

\titlespacing{\chapter}{0pt}{*0}{*4}

将章标题与左边、上边、下边内容的距离分别设为0pt, *0, *4。这里*n表示弹性 距离,对上距离来说相当于n ex plus .3ex minus .06ex, 对下距离来说相当于 n ex plus .1ex。弹性距离因为有一定的伸缩自由度,比较容易得到美观的排版。 如果想自己指定用关键字plus, minus定义的弹性距离,可以用星号版本的命令, 即

\titlespacing*{命令}{左距离}{上距离}{下距离}

上面设置了章标题的命令,用相同的命令也可以设置节、小节等的标题格式。但 如果没有特殊的要求,只希望修改一下标题头,可以用更加简单的命令 \titlelabel来设置。例如

\titlelabel{\S\thetitle\quad}

将章节标题设置为类似“§1 标题内容”的格式。这里\quad等于\hspace{1em}, 即 空出一个汉字宽度的距离。注意,\titleformat命令的定义会覆盖\titlelabel的 定义,而一般来说章跟节标题的格式不一样,所以只要另外用\titleformat命令 定义章标题的格式,\titlelabel的定义就只能作用于节以下层次的标题了。

这一节接着讲怎样用titlesec宏包提供的命令设置页眉、页脚。下面命令定义了 一个新的页面样式并使用该样式

\newpagestyle{main}{
    \sethead{}{}{\kai\small\chaptername\quad\chaptertitle\qquad\thepage}
    \setfoot{}{}{}\headrule}
\pagestyle{main}

其中\sethead命令设置页眉,格式为

\sethead[偶数页左页眉][偶数页中页眉][偶数页右页眉]
    {奇数页左页眉}{奇数页中页眉}{奇数页右页眉}

单面打印模式只要给出奇数页的设置即可,双面模式则需要将左、右页眉做个调 换。上面给出的例子是单面模式的。

\setfoot用来设置页脚,格式与\sethead类似。

在页眉、页脚里可以显示章节标题、页码等内容。如上面的例子就在页眉中显示 了章标题和页码。注意,\qquad相当于两个\quad, 即\hspace{2em}。

\headrule是划出页眉线,类似地\footrule划出页脚线,不过比较少用。默认页 眉线的宽度是0.4pt, 如果不满意,可以用下面命令重新设置其宽度

\setheadrule{宽度}

此外,还有两种特殊情况需要处理。首先,尽管在上面例子中用 \pagestyle{main}使用了自定义的页面样式,但每一章的第一页不受影响,仍然 使用默认的plain样式。在这种页面上,出于美观的考虑,一般不加页眉,而将页 码放在页脚(也有人喜欢不加页码)。所以plain样式(没有页眉,页码放在页脚中 间)已经基本符合要求,不必修改。如果需要修改,可定义一个新的页面样式,再 用下面命令重定义plain样式

\renewpagestyle{plain}{新的页面样式}

其次,在目录、参考文献或以\chapter*命令生成的章,上面页眉定义中的标题头 \chaptername是不应该显示的。所以有必要定义一个页面样式在这种特殊的章使 用,例如可以定义

\newpagestyle{special}{
    \sethead{}{}{\kai\small\chaptertitle\qquad\thepage}
    \setfoot{}{}{}\headrule}

然后在文中适当的地方用\pagestyle{special}改用该样式。

目录是学位论文的必要组成部分。只要在正文中适当的地方用

\tableofcontents

就可以自动生成目录。但是目录的格式不总是符合个人的要求,有时还要往其中 加一些条目。用titletoc宏包提供的命令可以方便地设置目录的格式。

首先可以用

\renewcommand{\contentsname}{目\quad 录}

将目录部分的标题改为中文。然后,用\titlecontents命令来设置不同级别目录 项的格式。例如,chapter层次的目录项格式可设置如下

\titlecontents{chapter}[0pt]{\vspace{.5\baselineskip}\bfseries}
    {第\CJKnumber{\thecontentslabel}章\quad}{}
    {\hspace{.5em}\titlerule*[10pt]{$\cdot$}\contentspage}

其中0pt是目录项到版芯左边界的距离。紧跟其后的是在排版目录项之前执行的命 令,这里\vspace{.5\baselineskip}表示与上文留出一定的垂直距离,该距离为 当前单倍行间距的一半。\bfseries把整条目录项的字体设为黑体。

后面一项是设置目录项的头部,这里设为“第一章”这样的格式,并在其后留出一 个汉字宽度的距离。紧跟的是设置目录项主体的格式,这里因为跟目录项头部相 同而空置。

再后面是设置填充命令和页码。这里先用\hspace{.5em}在目录项内容后面留出一 点空白,以免跟其后的填充点靠得太近。然后用\titlerule*命令画出填充点,这 里是把垂直居中的实心圆点作为填充符号(习惯上中文不采用居下的填充点), 并 以10pt为包含一个填充符号的水平盒子的宽度,即这个宽度越小,填充点越紧密。 填充点后加上页码\contentspage。

类似地可以设置section层次的目录项格式如下

\titlecontents{section}[2em]{\vspace{.25\baselineskip}}
    {\S\thecontentslabel\quad}{}
    {\hspace{.5em}\titlerule*[10pt]{$\cdot$}\contentspage}

其中2em表示section层次的目录项距左边界有一个缩进。如果还有subsection等 层次,可以类似地定义。

但是\chapter*, \section*等命令生成的标题不会自动进入目录中。例如中文摘 要部分如果用下面命令开始

\chapter*{摘\quad 要}

那么可以紧跟其后加上

\addcontentsline{toc}{chapter}{中文摘要}

就可以将中文摘要作为一个chapter层次插入目录中。英文摘要、参考文献部分均 可照此处理。随便提一下,参考文献部分的标题可用如下命令改为中文

\renewcommand{\bibname}{参考文献}

这一节讲前几节尚未提到的一些文本排版问题。

首先是行间距的设置。学校的学位论文规范中提到行间距为20pt。其实不同尺寸 的字体行间距都不相同,而是成比例关系。这个20pt是对正文主要字体来说的。 在TeX中基本的行间距是\baselineskip, 对于12pt的字体,这个值等于14.5pt, 而真正的行间距是

\baselineskip * \baselinestretch

\baselinestretch默认为1, 但我们可以重新设置它的值,如

\renewcommand{\baselinestretch}{1.38}

就得到真正的行间距为14.5pt*1.38≈20pt。而这样定义之后,对不同尺寸的字体 都会按同样的比例因子1.38放大行间距,使得全文排版能协调一致。

那么\baselineskip的值是怎么知道的呢?在TeX源文件中加上命令

\showthe\baselineskip

编译时就会暂停下来显示当前字体的\baselineskip值。用这个方法可以知 道,10pt字体对应的\baselineskip为12pt, 11pt字体对应的\baselineskip为 13.6pt。

至于通常所说的1.5倍行间距和双倍行间距,一般理解为字体基准尺寸的1.5倍和 2倍,例如对于12pt字体, 1.5倍行间距和双倍行间距分别应为12pt*1.5=18pt, 12pt*2=24pt。那么\baselinestretch分别应设为18pt/14.5pt≈1.24, 24pt/14.5≈1.66, 而不是1.5和2, 那样的话行间距就会显得过大了。

然后讲一下论文首页的设置。复旦的学位论文,装订的地方会按学校的模板制作 封面,就不用自己做了,不过规范中要求在扉页注明指导小组成员名单,并且为 了保持论文电子版的完整性,最好还是做一个简单的论文首页(标题页)。

没有必要用\title, \author和\maketitle等命令自动生成论文的标题,因为那可 能不太符合你的要求。只要用

\begin{titlepage}
标题页内容
\end{titlepage}

在标题页内容中用上一些center环境、\vspace*和字体选择命令就可以很容易地 设计出自己想要的格式了。

注意,上述标题页是没有页码的。而一般正文之前的部分,包括目录、摘要等, 习惯上采用与正文部分不同的页码格式,如用罗马数字表示,而从正文第一页开 始用阿拉伯数字重新开始计算页码。要做到这一点,只要在标题页后加上

\frontmatter 或 \pagenumbering{roman}

并在正文第一章前加上

\mainmatter 或 \pagenumbering{arabic}

就可以了。但是推荐使用\frontmatter和\mainmatter, 因为这两个命令的用处不 仅限于此。前面说过,像中文摘要这种非正文的部分,可以用\chapter*命令加 入,但当设置了页眉后就会发现一个问题,页眉中的\chaptertitle没有同步更新。 要解决这个问题,一个办法是在\chapter*命令后加上一句\chaptermark, 例如

\chapter*{摘\quad 要}\chaptermark{摘\quad 要}

但假如我们使用了\frontmatter, \mainmatter以及与其配套的\backmatter, 就 不需要这么麻烦,只要直接用不带星号版本的\chapter命令就可以了,对于 \frontmatter与\mainmatter之间的部分,以及\backmatter之后的部分,系统就 会自动地跟正文部分的章区别开来,不加上“第一章”这样的章标题头。一个典型 的文档结构示例如下

\begin{document}

\begin{titlepage}
标题页内容
\end{titlepage}

\frontmatter    % 开始正文之前的部分
\tableofcontents    % 自动生成目录

\chapter[中文摘要]{摘\quad 要}
% 方括号中是在目录中显示的内容,相当于前面使用的\addcontentsline
中文摘要内容

\chapter[英文摘要]{Abstract}
英文摘要内容

\mainmatter     % 开始正文部分
\chapter{第一章标题}
第一章内容

\backmatter     % 开始正文之后的部分
\begin{thebibliography}{99}\addcontentsline{toc}{chapter}{参考文献}
参考文献内容
\end{thebibliography}

\chapter[致谢]{致\quad 谢}
致谢内容

\end{document}

到这里文本排版讲得差不多了。这一节再讲讲定理和证明环境的格式设置。

数学论文里经常使用大量的定理环境。LaTeX默认的定理环境已经不能满足要 求,amsthm 宏包提供了方便的命令用于设置定理环境的格式。例如下面的命令定 义了一个定理样式mythm, 并用它来定义一些常用的定理环境

\newtheoremstyle{mythm}{1.5ex plus 1ex minus .2ex}{1.5ex plus 1ex minus .2ex}
    {\kai}{\parindent}{\song\bfseries}{}{1em}{}
\theoremstyle{mythm}
\newtheorem{thm}{定理~}
\newtheorem{lem}{引理~}
\newtheorem{prop}{命题~}
\newtheorem{cor}{推论~}
\newtheorem{defn}{定义~}
\newtheorem{conj}{猜想~}
\newtheorem{exmp}{例~}
\newtheorem{rem}{注~}

我们解释一下\newtheoremstyle命令里各项参数的意义。样式名称之后的两个长 度分别表示定理与上、下文之间的距离,这里均设为弹性距离。\kai是设置定理 内容的字体。\parindent是设置定理首行的缩进,在前面使用了\CJKindent的情 况下,它就等于2em。

紧随其后的\song\bfseries是设置定理头部即类似“定理 1”部分的格式,一般中 文使用黑体。因为我们在前面已经将宋体对应的粗体定义为黑体,所以这里将中 文字体设为宋体,再用选择粗体命令\bfseries, 就同时把中文变为黑体,英文变 为粗体了。注意,如果前面没有修改字体定义文件,而在这里用\hei改变字体, 再加上\bfseries就很可能会造成“黑上加黑”即黑体的加粗,这种拙劣的文本效果 是不应该出现的。

这之后的参数是设置紧跟定理头部的符号,英文中常设为一句点,而中文习惯不 加任何符号,所以这里空置。然后是设置定理头部与定理内容之间的空白距离, 这里设为1em, 即一个汉字的宽度。

最后一项是对定理头部的补充说明,这里空置。但如果我们希望得到类似“定理 1 (存在性定理)”这样的定理头部,那么可以再定义一种定理样式

\newtheoremstyle{specthm}{1.5ex plus 1ex minus .2ex}{1.5ex plus 1ex minus 
    .2ex}{\kai}{\parindent}{\song\bfseries}{}{1em}{\thmnote{#3}}

这里最后一项\thmnote{#3}表示用方括号中的附加内容作为定理头部。用此样式 定义一个新的定理环境(与前面定义过的thm环境统一编号)

\theoremstyle{specthm}
\newtheorem{sthm}[thm]{}

并在正文中使用

\begin{sthm}[定理~\thethm~(存在性定理)]
定理内容
\end{sthm}

就得到了想要的效果。

至于证明的排版,amsthm宏包提供了proof环境,但格式需要做一点调整。 amsthm.sty中对proof环境的定义如下

\newenvironment{proof}[1][\proofname]{\par
    \pushQED{\qed}%
    \normalfont \topsep6\p@\@plus6\p@\relax
    \trivlist
    \item[\hskip\labelsep
        \itshape
      #1\@addpunct{.}]\ignorespaces
}{%
    \popQED\endtrivlist\@endpefalse
}

为了符合一般中文证明环境的排版习惯,可以重新定义proof环境为(注意,因为 这些命令含有@字符,所以需要在前、后分别加上\makeatletter和 \makeatother)

\makeatletter
\renewenvironment{proof}[1][\proofname]{\par
    \pushQED{\qed}%
    \normalfont \topsep6\p@\@plus6\p@ \labelsep1em\relax
    \trivlist
    \item[\hskip\labelsep\indent
        \bfseries #1]\ignorespaces
}{%
    \popQED\endtrivlist\@endpefalse
}
\makeatother

并且重新定义\proofname为

\renewcommand{\proofname}{证明}

proof环境会自动在证明最后一行的最右边加上一个证明结束符,默认为空心方 块,可以重新定义\qedsymbol来修改它。需要注意的是,当证明以一个独立公式 结束时,证明结束符会出现在下一行的最右边,而不是在公式的同一行上,这不 合乎习惯。这时只要在公式环境内加上\qedhere即可。

最后还要讲讲浮动图形和表格环境的中文化。首先把Figure和Table改为中文

\renewcommand{\figurename}{图}
\renewcommand{\tablename}{表}

然后需要对浮动环境的标题格式做一点修改。在book.cls中可以找到如下定义

\long\def\@makecaption#1#2{%
  \vskip\abovecaptionskip
  \sbox\@tempboxa{#1: #2}%
  \ifdim \wd\@tempboxa >\hsize
    #1: #2\par
  \else
    \global \@minipagefalse
    \hb@xt@\hsize{\hfil\box\@tempboxa\hfil}%
  \fi
  \vskip\belowcaptionskip}

这段代码包括了一个判断选择结构,如果标题超过一行则直接显示,否则在一行 内居中显示。可以不理会这个,只要根据自己的格式要求修改#1(即\figurename 或\tablename) 和#2(标题内容)的格式,以及#1与#2之间的分隔符。例如,如果 希望把#1改为黑体,并把分隔符改为一个空格,可以这样设置

\makeatletter
\long\def\@makecaption#1#2{%
  \vskip\abovecaptionskip
  \sbox\@tempboxa{{\bfseries #1}\quad #2}%
  \ifdim \wd\@tempboxa >\hsize
    {\bfseries #1}\quad #2\par
  \else
    \global \@minipagefalse
    \hb@xt@\hsize{\hfil\box\@tempboxa\hfil}%
  \fi
  \vskip\belowcaptionskip}
\makeatother

★★★结束语★★★

到这里,每个人都需要知道的东西已经基本上介绍完了。如果你仔细读了这些文 字,并且按照它去设置了你的论文格式,我想应该差不多了。当然,不同学科的 论文有各自的特点和要求,肯定还有很多具体的问题没有涉及。例如计算机专业 的可能经常要用到代码抄录环境,文科的论文可能要使用章末注,等等。这些问 题也是版上经常问到的,在本版精华区中大都能找到解答,这里就不再赘述。

希望费了不少时间写的这些东西能对大家有所帮助。最后,祝大家TeX越用越熟 练,都能写出漂亮的论文!

GNU Screen

blog.csdn.net/coldwindflyrain/archive/2008/04/01/2234566.aspx

GNU Screen -- MITBBS Linux版镇版之宝

* 什么是GNU Screen

常来我们版的,基本上就算没有自己用过也听说过screen的名字了,那么到底什
么是screen, 它又是干什么的呢?为什么它能称得上是我们的镇版之宝?

screen的手册上说了,screen是一个terminal multiplexer。但是对于普通人来
讲,这个定义和没有定义差不多。我觉得最通俗的解释,应该说screen相当于文
本界面下面的一个desktop,就像GNOME, KDE之于X窗口系统。其次,screen还提
供类似于远程桌面(freenx, vnc, 或者Windows下的remote desktop)的功能,
你可以在本地生成一个"桌面",然后通过网络重新连到这个"桌面",所有你开的
"窗口"都还在。从这一点上说,screen完全可以取代nohup帮助你远程跑长时间的
程序,比如说需要过夜计算的simulation之类。

* Screen的基本功能

在我们谈screen的基本功能之前,我们来看看一个现代desktop,比如说gnome,
到底都为用户提供了什么。

首先,gnome提供了一个多窗口管理机制。以前这一块由metacity提供,现在很多
情况下是由compiz fusion 3D窗口管理器管。无论是老土的metacity还是眩目的
compiz fusion,其实说穿了都不过是给用户一个机制来管理多个同时运行的图形
化程序。广而论之,X下面的virtual desktop也不过是这个机制的延伸。

其次,gnome提供了一个(或者多个)panel,这个panel上可以加载很多有用的插
件。其中最有用的是window list,显示出你当前打开的几个应用程序的名字,然
后提供一个切换的方法。

第二有用的panel插件大概就是system monitor吧,能够显示出系统当前的
loads, memory等等。有的人大概还喜欢在panel上面显示时间,机器名等等信息。

再接下来,gnome还提供了一些别的服务,比如说程序与程序间的copy/paste服务,
设置多语言编码方式,键盘热键设定,必要的时候把屏幕锁上等等。

我们很快就能看到,以上说的这些功能,都有screen下的对应。当然,gnome是个
庞然大物,里头还有无数应用程序,就是那些以g开头的无数程序。但这些严格的
讲并不是一个桌面系统的一部分。甚至连nautilus严格的讲也不能算是desktop里
头不可分割的一部分。这些应用程序其实很多在文本界面下也有对应物,只不过
不由screen负责而已。我会在本文里头附带稍微介绍一下一些文本模式下的应用
程序。

* Screen的基本操作

** 第一次启动screen

每一个screen进程本身代表一个session. 最简单的方法是在一个终端下直接输入
screen然后回车。这时你会看到一个很简陋的greeting界面,然后你随便按一个
空格它就消失了,剩下的就是普通的shell提示符,好像什么都没发生过。你可以
运行一些标准shell指令,比如说ls,你会发现这个shell和别的shell没有任何不
同。

运行如下命令

screen -ls

你会发现它告诉你有一个screen在跑:

$ screen -ls
There is a screen on:
8671.pts-1.inferno (Attached)
1 Socket in /var/run/screen/S-qiuxing.

现在你输入Ctrl-a, 然后单个字母w,会发现左下角出现一个提示,比如说:

0*$ bash

现在再按Ctrl-a然后d,这时你开头运行命令出现的那些文字都不见了。我们现在再来
跑一次screen -ls:

$ screen -ls
There is a screen on:
8671.pts-1.inferno (Detached)
1 Socket in /var/run/screen/S-qiuxing

什么都没变除了状态由Attached变成了Detached。

现在你把你刚刚用的xterm关掉,重开一个xterm,或者有条件的话换一部电脑,
ssh到你的第一部机器,然后输入screen -r。你看见了什么?是不是之前的那些
文字都又回来了?

其实真正发生的是这么一个过程:screen创建了一个socket(一般是在
/var/run/screen/下面),把它伪装成为一个虚拟文本终端(pty device)来充当
标准输入输出设备,然后调用了一个shell 程序让它运行在这个文本终端(其实
是个socket)上。当你从一个xterm里头detach掉了screen,screen下运行的程序
不会直接退出,因为它们用的标准输入输入装置已经不是你的xterm(下面跑的那
个shell)所相关的那个虚拟文本终端,而是一个socket了。

** 管理session

一般来说,我们不会裸起一个screen. 好的practice是每次新开一个screen,都
给它取一个好记的名字:

screen -S a_name

下次再用screen -ls的时候就会发现它有一个名字了(就是随机数后面的那一部
分)。

以下为和管理session有关的命令:

- 检查有多少screen session和它们的状态用screen -ls
- detach一个正在跑的session用Ctrl-a d
- reattach这个session用screen -r,
- 如果有多个detached的session, 而我们又想attach到某一个的话,就用screen
-r a_name
- 在一个正在跑的session里头改名字: 先按Ctrl-a, 然后按冒号:, 出来一个类
似vi的输入命令的界面,在里头运行这个内部命令:sessionname a_name

一个很常见的情况:有时我们需要强制reattach到一个attached session,比如
说忘记detach了,或者是ssh的时候网络断线了. 这个命令是: screen -RD
a_name. 事实上它的实现是先给a_name session发出一个detach指令,然后在发
出一个attach指令。

** 管理窗口

- 生成一个新的窗口: Ctrl-a c。这个新的窗口跑的是你的shell。
- 生成一个新的窗口,并且让它跑某个指定的程序: Ctrl-a :, 然后输入:
screen -t <name> <n> <command> 其中<name>是窗口的名字,<n>是窗口号,
<command>是指定的程序。这个命令主要是在配置文件里头用。
- 关闭一个窗口: 退出这个窗口的程序,则窗口自动关闭
- 在无法退出某个程序的时候强制关闭一个窗口: Ctrl-a K
- 窗口列表: Ctrl-a w
- 窗口切换:
1. Ctrl-a ", 出现一个菜单可以选择
2. Ctrl-a <n>, <n>是从0到9的窗口ID,这个命令直接切换到第<n>号窗口
3. Ctrl-a SPACE, 下一个窗口
4. Ctrl-a BACKSPACE, 前一个窗口
5. Ctrl-a Ctrl-a, 在当前和前一个窗口之间转换,相当于Alt-Tab的功能
- 窗口改名: Ctrl-a A

** 分屏

- 上下分成两个区域: Ctrl-a S (相当于emacs里的C-x 2
- 在两个区域里头切换: Ctrl-a TAB
- 合并两个区域: Ctrl-a Q (相当于emacs里的C-x 1), Ctrl-a X (相当于
emacs里头的C-x 0)

** copy/paste

正常模式下screen把所有的不以Ctrl-a开头的命令都完全透明地pass给窗口里
头的程序了。其实screen还有一个copy/paste模式,进入这个模式后screen的行
为就更像一个text editor(vi),你可以copy/paste,也可以上下移动(相当于
scroll window)。

- 进入copy/paste mode: Ctrl-a ESC或者Ctrl-a [.
- 在c/p mode下移动光标: 上下左右箭头,pgup/pgdown等。vi的hjkl,BE,/?等
等也都work
- Set mark: SPACE (类似emacs里面的Ctrl-SPACE)
- 两个mark里的内容自动进入screen的c/p buffer, 并且退出c/p mode。
- 这个c/p buffer还可以用文件写出来: Ctrl-a >

在正常模式下,Ctrl-a ]能够paste刚刚选中的内容。

** 其它有用功能/注意事项

第一重要的注意事项: 不要乱按Ctrl-a s. 它会锁死你的shell。不过不小心碰
到了也别怕,再按一下Ctrl-a q,你的shell就活过来了。

第二重要的事情: 我习惯了在shell/emacs里用Ctrl-a而不是Home跳到句首。可
是现在Ctrl-a被screen占用了。那么,我们怎么输入一个Ctrl-a? 答案: Ctrl-a
再加字母a.

推论: 如果在一个screen里头不小心attach了另外一个screen怎么办? 用Ctr-a
a d来detach里头的那个screen.

- 查看系统时间等信息: Ctrl-a t
- 查看screen本身的信息: Ctrl-a v
- 锁住屏幕: Ctrl-a x
- 清理屏幕: Ctrl-a l
- 有时候screen会显示一些信息,想要显示上一次显示的提示内容的话:
Ctrl-a m
- 给当前窗口录像(生成一个log,记录所有的信息): Ctrl-a H
- 使用visual bell: Ctrl-a Ctrl-g

* 配置文件

screen的基本配置文件是~/.screenrc(用户目录下的一个隐藏文件)。事实上在
这里控制的screen参数都可以在一个正在跑的screen里面通过进入命令行模式
(Ctrl-a :),输入相关命令来实现。但写配置文件可以省不少重复性的工作。

启动screen时有一个"-c"的参数来使用任何一个指定文件作为配置文件。比如:

screen -c .screenrc2

附录里有一个screenrc文件例子,里头详细的注释了每一行是干什么的。

* 高级用法

** 关注某个窗口

有时候我们可能开了一个窗口来跑一个要跑很久的程序,又或者那个窗口跑的是
pine/mutt,但我们在另外一个窗口干活。绝大多数时候第一个窗口都不会有任何
信息,但假设出现了变化比如说程序跑完了或者收到了新的email,我们也希望能
够在干活的当前窗口得到一个提示。

还有另外一种相反的情况,比如说编译一个大程序,不断的会出各种信息。但如
果不出了,那就说明编译完了(或者错了),这时候我们也希望得到通知。这个
功能大约对于Gentoo用户来说是最有用的.

这些都可以通过打开/关闭monitoring来实现。

- Ctrl-a M. 这样当前窗口如果出现变化,系统会通过message来通知你
- Ctrl-a _. 正好是上面的反面,如果当前窗口15秒都没动静了,则screen会发
一个msg.

** caption/hardstatus line

之前我提到过screen可以实现类似于gnome panel的功能。这个功能在screen里面
叫做caption line或者hardstatus line。它的配置看起来比较复杂,但一旦搞明
白了你就可以用它干很多很cool的事情。一个类比是配置bash的提示符,也是属
于不大好配置但很强大的东西。

我先举一个简单的例子吧:

caption always "%{+b Yk}%w"
hardstatus alwayslastline "Host: %H Load: %l "

它的效果是出现了两条panel, 第一条叫做caption line, 里头的内容是带颜色的
窗口信息, 第二条是hardstatus line, 里头有host和system load的信息。

在"%{+b Yk}%w"里头,%是escape sequence,+b是指粗体,Yk指的是亮黄(Y)字体,
配黑色(k)背景,%w是窗口号/名字。hardstatus bar里面,%H是hostname, %l是
系统load(和top里头显示的一样),其他就是一般的字符。

下面是一个比较复杂的hardstatus line配置, 视觉效果比单纯的%w要好:

hardstatus alwayslastline '%{Yk}%-w%{.Yk}%n %t%{-}%+w %=%{.w}'

更多的色彩,信息,请参阅screen manual里头关于string escapes那一章。

** Panel插件

虽然screen提供了很多string escapes, 但它们还是不可能满足所有人所有的需
要。比如说我自己就想知道系统使用了多少内存,有的人可能还想查看有没有新
邮件,等等。在gnome panel里头,这些都是通过panel插件来实现的。在screen
的caption/hardstatus line里也有一个类似的机制,让你把任何一个指定的程序
的output放在panel上。

一个简单的例子:

backtick 1 5 5 uptime
hardstatus alwayslastline "%1`"

解释一下:backtick 1 5 5 uptime的意思是定义外部命令uptime的标准输出作为
一个string escape, ID为1. 一次显示5秒钟,5秒钟之后重新运行一次。

比较复杂的例子(这也是我自己在用的screenrc):

backtick 1 5 5 /home/qiuxing/bin/my_sysload1
backtick 2 5 5 /home/qiuxing/bin/my_free

hardstatus string '%{Yk}%-w%{.Yk}%n %t%{-}%+w %=%{.w} %{.Yr}%1` %{.Yb}%2`M %
{kY}%C'

其中my_sysload1和my_free的内容如下:

my_sysload1:

#!/bin/bash
cat /proc/loadavg | cut -d" " -f1

my_free:
free -m | tail -n 2 | head -n 1 | cut -c27-29

** 256色

比较新的screen支持256色。如果自己编译,记得在编译的时候打开这个选项。
Feisty和之前的Ubuntu下的screen没有加这个编译选项,但在Gutsy里这个选项已
经有了。我知道的支持256色的程序有vi/emacs/elinks。如果你知道别的文本模
式程序支持256色,请务必让我知道。

如果你知道你的screen支持256色,请在.screenrc里头加入这么几句:

term xterm-256color
attrcolor b ".I"
termcapinfo xterm-256color 'Co#256:AB=\E[48;5;%dm:AF=\E[38;5;%dm'
defbce "on"

其中第一句让screen伪装成一个xterm-256color,第二句让screen使用bold字体,
第三句告诉screen怎么定义前景背景等信息,最后一句是让screen用背景色来
erase text。

另外要确认一下你的系统上的确有xterm-256color这个term的信息。在Ubuntu里,
这个库叫做ncurses-term。

** X/鼠标支持

有一些文本程序也支持鼠标(emacs, elinks, w3m),有的甚至还支持inline
picture display(w3m)。screen对于这些都支持得很好。只要记住远程连接的时
候打开X11 forwarding开关(ssh -X),另外要检查一下shell变量DISPLAY是不
是设置对了(本地显示应该是:0.0,远程一般是:10.0之类的东西)。

** 编码转换

screen还有一个鲜为人知的功能:实现编码转换。比如说mrxvt只能支持gbk,但
不能支持unicode。可是我的中文文件都是unicode编码的。这时就可以通过
screen来实现编码转换:

encoding GBK UTF-8

只要在一个支持unicode的terminal里头生成一个screen session,detach之,下
次在一个编码为zh_CN.gbk的mrxvt里头reattach上这个session,所有的
zh_CN.utf8编码的中文文字就会自动转换为gbk格式。

** 多用户支持

screen还可以支持多用户。也就是说一个用户生成了一个session,然后让guest
来参与。具体的做法是先让screen变成一个setuid root的程序,然后在
screenrc里头允许另外一个用户连接。

如果你用过这个功能就会发现它相当的cool。但因为有一定的security concern,
我就不写太详细了。真要想用的话请参照这个Gentoo howto:

http://gentoo-wiki.com/HOWTO_Snoop_terminal_session#Screen

* 附录

** screenrc文件范例

# 和256色相关的配置
term xterm-256color
attrcolor b ".I"
termcapinfo xterm-256color 'Co#256:AB=\E[48;5;%dm:AF=\E[38;5;%dm'
defbce "on"

# 编码转换
encoding GBK UTF-8

# 使用visual bell
vbell on

# 断线的时候自动detach
autodetach on

# 不要出来那个烦人的greeting
startup_message off

# make the shell in every window a login shell
# 意思是会去执行~/.bash_profile
shell -$SHELL

# 在copy/paste模式下可以回溯到5000行的历史
defscrollback 5000

#remove some stupid / dangerous key bindings
bind k
bind ^k
bind .
bind ^\
bind \\
bind ^h
bind h
#make them better
bind 'K' kill
bind 'I' login on
bind 'O' login off
bind '}' history

# default windows

screen -t work 0
screen -t shell 1
screen -t su 3 sudo su -
screen -t others 4
chdir /home/qiuxing/Documents/writing/linux
screen -t notes 5
chdir
screen -t mutt 6 mutt
select 0

# hardstatus line hack
backtick 1 5 5 /home/xqiu/bin/my_sysload1
backtick 2 5 5 /home/xqiu/bin/my_free

hardstatus alwayslastline '%{Yk}%-w%{.Yk}%n %t%{-}%+w %=%{.w} %{.Yr}%1` %{.
Yb}%2`M %{kY}%C'

让进程在后台可靠运行的几种方法

www.ibm.com/developerworks/cn/linux/l-cn-nohup/index.html
想让进程在断开连接后依然保持运行?如果该进程已经开始运行了该如何补救? 如果有大量这类需求如何简化操作?

我们经常会碰到这 样的问题,用 telnet/ssh 登录了远程的 Linux 服务器,运行了一些耗时较长的任务, 结果却由于网络的不稳定导致任务中途失败。如何让命令提交后不受本地关闭终端窗口/网络断开连接的干扰呢?下面举了一些例子, 您可以针对不同的场景选择不同的方式来处理这个问题。

nohup/setsid/&

场景:

如果只是临时有一个命令需要长时间运行,什么方法能最简便的保证它在后台稳定运行呢?

hangup 名称的来由
在 Unix 的早期版本中,每个终端都会通过 modem 和系统通讯。当用户 logout 时,modem 就会挂断(hang up)电话。 同理,当 modem 断开连接时,就会给终端发送 hangup 信号来通知其关闭所有子进程。

解决方法:

我们知道,当用户注销(logout)或者网络断开时,终端会收到 HUP(hangup)信号从而关闭其所有子进程。因此,我们的解决办法就有两种途径:要么让进程忽略 HUP 信号,要么让进程运行在新的会话里从而成为不属于此终端的子进程。

1. nohup

nohup 无疑是我们首先想到的办法。顾名思义,nohup 的用途就是让提交的命令忽略 hangup 信号。让我们先来看一下 nohup 的帮助信息:

NOHUP(1)                        User Commands                        NOHUP(1)

NAME
       nohup - run a command immune to hangups, with output to a non-tty

SYNOPSIS
       nohup COMMAND [ARG]...
       nohup OPTION

DESCRIPTION
       Run COMMAND, ignoring hangup signals.

       --help display this help and exit

       --version
              output version information and exit 

 

可见,nohup 的使用是十分方便的,只需在要处理的命令前加上 nohup 即可,标准输出和标准错误缺省会被重定向到 nohup.out 文件中。一般我们可在结尾加上"&"来将命令同时放入后台运行,也可用">filename 2>&1"来更改缺省的重定向文件名。


nohup 示例

                
[root@pvcent107 ~]# nohup ping www.ibm.com &
[1] 3059
nohup: appending output to `nohup.out'
[root@pvcent107 ~]# ps -ef |grep 3059
root      3059   984  0 21:06 pts/3    00:00:00 ping www.ibm.com
root      3067   984  0 21:06 pts/3    00:00:00 grep 3059
[root@pvcent107 ~]#	 


2。setsid

nohup 无疑能通过忽略 HUP 信号来使我们的进程避免中途被中断,但如果我们换个角度思考,如果我们的进程不属于接受 HUP 信号的终端的子进程,那么自然也就不会受到 HUP 信号的影响了。setsid 就能帮助我们做到这一点。让我们先来看一下 setsid 的帮助信息:

SETSID(8)                 Linux Programmer’s Manual                 SETSID(8)

NAME
       setsid - run a program in a new session

SYNOPSIS
       setsid program [ arg ... ]

DESCRIPTION
       setsid runs a program in a new session. 

 

可见 setsid 的使用也是非常方便的,也只需在要处理的命令前加上 setsid 即可。


setsid 示例

                
[root@pvcent107 ~]# setsid ping www.ibm.com
[root@pvcent107 ~]# ps -ef |grep www.ibm.com
root     31094     1  0 07:28 ?        00:00:00 ping www.ibm.com
root     31102 29217  0 07:29 pts/4    00:00:00 grep www.ibm.com
[root@pvcent107 ~]#   

 

值得注意的是,上例中我们的进程 ID(PID)为31094,而它的父 ID(PPID)为1(即为 init 进程 ID),并不是当前终端的进程 ID。请将此例与nohup 例中的父 ID 做比较。

3。&

这里还有一个关于 subshell 的小技巧。我们知道,将一个或多个命名包含在“()”中就能让这些命令在子 shell 中运行中,从而扩展出很多有趣的功能,我们现在要讨论的就是其中之一。

当我们将"&"也放入“()”内之后,我们就会发现所提交的作业并不在作业列表中,也就是说,是无法通过jobs来查看的。让我们来看看为什么这样就能躲过 HUP 信号的影响吧。


subshell 示例

                
[root@pvcent107 ~]# (ping www.ibm.com &)
[root@pvcent107 ~]# ps -ef |grep www.ibm.com
root     16270     1  0 14:13 pts/4    00:00:00 ping www.ibm.com
root     16278 15362  0 14:13 pts/4    00:00:00 grep www.ibm.com
[root@pvcent107 ~]#   

 

从上例中可以看出,新提交的进程的父 ID(PPID)为1(init 进程的 PID),并不是当前终端的进程 ID。因此并不属于当前终端的子进程,从而也就不会受到当前终端的 HUP 信号的影响了。

 


 

disown

场景:

我们已经知道,如果事先在命令前加上 nohup 或者 setsid 就可以避免 HUP 信号的影响。但是如果我们未加任何处理就已经提交了命令,该如何补救才能让它避免 HUP 信号的影响呢?

解决方法:

这时想加 nohup 或者 setsid 已经为时已晚,只能通过作业调度和 disown 来解决这个问题了。让我们来看一下 disown 的帮助信息:

disown [-ar] [-h] [jobspec ...]
	Without options, each jobspec is  removed  from  the  table  of
	active  jobs.   If  the -h option is given, each jobspec is not
	removed from the table, but is marked so  that  SIGHUP  is  not
	sent  to the job if the shell receives a SIGHUP.  If no jobspec
	is present, and neither the -a nor the -r option  is  supplied,
	the  current  job  is  used.  If no jobspec is supplied, the -a
	option means to remove or mark all jobs; the -r option  without
	a  jobspec  argument  restricts operation to running jobs.  The
	return value is 0 unless a jobspec does  not  specify  a  valid
	job.

 

可以看出,我们可以用如下方式来达成我们的目的。

灵活运用 CTRL-z
在我们的日常工作中,我们可以用 CTRL-z 来将当前进程挂起到后台暂停运行,执行一些别的操作,然后再用 fg 来将挂起的进程重新放回前台(也可用 bg 来将挂起的进程放在后台)继续运行。这样我们就可以在一个终端内灵活切换运行多个任务,这一点在调试代码时尤为有用。因为将代码编辑器挂起到后台再重新放 回时,光标定位仍然停留在上次挂起时的位置,避免了重新定位的麻烦。
  • disown -h jobspec 来使某个作业忽略HUP信号。
  • disown -ah 来使所有的作业都忽略HUP信号。
  • disown -rh 来使正在运行的作业忽略HUP信号。

需要注意的是,当使用过 disown 之后,会将把目标作业从作业列表中移除,我们将不能再使用jobs来查看它,但是依然能够用ps -ef查找到它。

但是还有一个问题,这种方法的操作对象是作业,如果我们在运行命令时在结尾加了"&"来使它成为一个作业并在后台运行,那么就万事大吉了,我们可以通过jobs命令来得到所有作业的列表。但是如果并没有把当前命令作为作业来运行,如何才能得到它的作业号呢?答案就是用 CTRL-z(按住Ctrl键的同时按住z键)了!

CTRL-z 的用途就是将当前进程挂起(Suspend),然后我们就可以用jobs命令来查询它的作业号,再用bg jobspec 来将它放入后台并继续运行。需要注意的是,如果挂起会影响当前进程的运行结果,请慎用此方法。


disown 示例1(如果提交命令时已经用“&”将命令放入后台运行,则可以直接使用“disown”)

                
[root@pvcent107 build]# cp -r testLargeFile largeFile &
[1] 4825
[root@pvcent107 build]# jobs
[1]+  Running                 cp -i -r testLargeFile largeFile &
[root@pvcent107 build]# disown -h %1
[root@pvcent107 build]# ps -ef |grep largeFile
root      4825   968  1 09:46 pts/4    00:00:00 cp -i -r testLargeFile largeFile
root      4853   968  0 09:46 pts/4    00:00:00 grep largeFile
[root@pvcent107 build]# logout   



disown 示例2(如果提交命令时未使用“&”将命令放入后台运行,可使用 CTRL-z 和“bg”将其放入后台,再使用“disown”)

                
[root@pvcent107 build]# cp -r testLargeFile largeFile2

[1]+  Stopped                 cp -i -r testLargeFile largeFile2
[root@pvcent107 build]# bg %1
[1]+ cp -i -r testLargeFile largeFile2 &
[root@pvcent107 build]# jobs
[1]+  Running                 cp -i -r testLargeFile largeFile2 &
[root@pvcent107 build]# disown -h %1
[root@pvcent107 build]# ps -ef |grep largeFile2
root      5790  5577  1 10:04 pts/3    00:00:00 cp -i -r testLargeFile largeFile2
root      5824  5577  0 10:05 pts/3    00:00:00 grep largeFile2
[root@pvcent107 build]#   

 


 

screen

场景:

我们已经知道了如何让进程免受 HUP 信号的影响,但是如果有大量这种命令需要在稳定的后台里运行,如何避免对每条命令都做这样的操作呢?

解决方法:

此时最方便的方法就是 screen 了。简单的说,screen 提供了 ANSI/VT100 的终端模拟器,使它能够在一个真实终端下运行多个全屏的伪终端。screen 的参数很多,具有很强大的功能,我们在此仅介绍其常用功能以及简要分析一下为什么使用 screen 能够避免 HUP 信号的影响。我们先看一下 screen 的帮助信息:

SCREEN(1)                                                           SCREEN(1)

NAME
       screen - screen manager with VT100/ANSI terminal emulation

SYNOPSIS
       screen [ -options ] [ cmd [ args ] ]
       screen -r [[pid.]tty[.host]]
       screen -r sessionowner/[[pid.]tty[.host]]

DESCRIPTION
       Screen  is  a  full-screen  window manager that multiplexes a physical
       terminal between several  processes  (typically  interactive  shells).
       Each  virtual  terminal provides the functions of a DEC VT100 terminal
       and, in addition, several control functions from the  ISO  6429  (ECMA
       48,  ANSI  X3.64)  and ISO 2022 standards (e.g. insert/delete line and
       support for multiple character sets).  There is a  scrollback  history
       buffer  for  each virtual terminal and a copy-and-paste mechanism that
       allows moving text regions between windows.	

 

使用 screen 很方便,有以下几个常用选项:

  • screen -dmS session name 来建立一个处于断开模式下的会话(并指定其会话名)。
  • screen -list 来列出所有会话。
  • screen -r session name 来重新连接指定会话。
  • 用快捷键CTRL-a d 来暂时断开当前会话。


screen 示例

                
[root@pvcent107 ~]# screen -dmS Urumchi
[root@pvcent107 ~]# screen -list
There is a screen on:
        12842.Urumchi   (Detached)
1 Socket in /tmp/screens/S-root.

[root@pvcent107 ~]# screen -r Urumchi	 

 

当我们用“-r”连接到 screen 会话后,我们就可以在这个伪终端里面为所欲为,再也不用担心 HUP 信号会对我们的进程造成影响,也不用给每个命令前都加上“nohup”或者“setsid”了。这是为什么呢?让我来看一下下面两个例子吧。


1. 未使用 screen 时新进程的进程树

                
[root@pvcent107 ~]# ping www.google.com &
[1] 9499
[root@pvcent107 ~]# pstree -H 9499
init─┬─Xvnc
     ├─acpid
     ├─atd
     ├─2*[sendmail]	
     ├─sshd─┬─sshd───bash───pstree
     │       └─sshd───bash───ping
            

 

我们可以看出,未使用 screen 时我们所处的 bash 是 sshd 的子进程,当 ssh 断开连接时,HUP 信号自然会影响到它下面的所有子进程(包括我们新建立的 ping 进程)。


2. 使用了 screen 后新进程的进程树

                
[root@pvcent107 ~]# screen -r Urumchi
[root@pvcent107 ~]# ping www.ibm.com &
[1] 9488
[root@pvcent107 ~]# pstree -H 9488
init─┬─Xvnc
     ├─acpid
     ├─atd
     ├─screen───bash───ping
     ├─2*[sendmail]	

 

而使用了 screen 后就不同了,此时 bash 是 screen 的子进程,而 screen 是 init(PID为1)的子进程。那么当 ssh 断开连接时,HUP 信号自然不会影响到 screen 下面的子进程了。

 


 

总结

现在几种方法已经介绍完毕,我们可以根据不同的场景来选择不同的方案。nohup/setsid 无疑是临时需要时最方便的方法,disown 能帮助我们来事后补救当前已经在运行了的作业,而 screen 则是在大批量操作时不二的选择了。

portage-utils和eix的一些常用命令选项


#------------------------------------------------------------------------------
qfile <filename>
Options: -[ef:m:oRx:vqChV]
-e, --Exact          *精确匹配,类似eix -e gcc只查到包名为gcc的包效果一样
-f, --from <arg>     *Read arguments form file <arg> ("-" for stdio)
                     *将读入文件作为qfile的输入(有待考证)

-m, --max-args <arg> * Treat from file arguments by groups of args(默认为5000)
-o, --orphans        *显示孤立文件 这个是显示孤儿文件,就是不包含在任何安装包里边的文件。(不是通过ebuild安装的,可能是你手工安装的程序,也可能是反删除时候留下的文件),这个一般用来清除系统垃圾文件。
-R, --root-prefix, Assume arguments are already prefixed by $ROOT
                     *假设已将参数前缀设置为$ROOT了(不知如何表达)

-x, --exclude <arg>  * Don't look in package <arg>排除xxxx

<注>当equery b filename时未找到匹配时可以试试qfile,可能会给你带来惊喜
#------------------------------------------------------------------------------

    
#------------------------------------------------------------------------------
qlop <opts> <pkgname>
-g, --gauge      * Gauge number of times a package has been merged
                   比较准确估算出一个包已merged的时间

-t, --time       *计算一个指定包merge的时间
-H, --human      *输出的是秒形式,所以用此参数转化为人性化的显示方式(需要-t参数的支持)
-l, --list       *显示merge历史
-u, --unlist     *显示unmerge 历史
-c, --current    *显示当前正在emerging的包,相当于genlop -c

-f, --logfile <arg> *Read emerge logfile instead of /var/log/emerge.log
                    *用logfile的文件来代替/var/log/emerge.log 
#------------------------------------------------------------------------------


#------------------------------------------------------------------------------
quse <opts> <useflag>
-e, --exact          *精确比较,不使用正则表达式
-a, --all            *Show annoying things in IUSE (不管3721全显)
-K, --keywords       *Use the KEYWORDS vs IUSE
-L, --license        *Use the LICENSE vs IUSE
-D, --describe       *显示USE的描述信息,类似 euse -i xxx
-F, --format   <arg> * Use your own variable formats. -F NAME=
-N, --name-only      * Only show package name
#------------------------------------------------------------------------------


#------------------------------------------------------------------------------
qcheck <opts> <pkgname>
-e, --exact          *Exact match (only CAT/PN or PN without PV)
-a, --all            *显示所有包
-u, --update         *更新包的缺失的文件,校验码和修改时间(不要乱用)
-A, --noafk          *忽略缺失的文件
-H, --nohash         *Ignore differing/unknown file chksums
-T, --nomtime        *Ignore differing file mtimes
-v, --verbose
#------------------------------------------------------------------------------

#------------------------------------------------------------------------------
qsize <opts> <pkgname>
-f, --filesystem    *显示已使用的磁盘空间(包占用大小)
-a, --all           *显示所有安装包的大小
-s, --sum           *Include a summary 还会显示一个总和
-S, --sum-only      *仅显示总和 
-m, --megabytes     *用M方式显示 xMbytes
-k, --kilobytes     *用K方式显示 Kbytes
-b, --bytes
-v, --version
#------------------------------------------------------------------------------

#------------------------------------------------------------------------------
qdepends <opts> <pkgname>
-d, --depend        *显示依赖信息
-r, --rdepend       *显示反向依赖信息
-p, --pdepend       *显示PDEPEND信息 (未理解到)
-k, --key <arg>     *User defined vdb key
-Q, --query <arg>   *查询反向依赖
-N, --name-only     *仅显示包名
-a, --all           *显示所有依赖信息
-v, --verbose
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------

Usage: qtbz2 <opts> <misc args> : manipulate tbz2 packages

Options: -[jstxOvqChV]
  -j, --join           * Join tar.bz2 + xpak into a tbz2
  -s, --split          * Split a tbz2 into a tar.bz2 + xpak
  -t, --tarbz2         * Just split the tar.bz2
  -x, --xpak           * Just split the xpak
  -O, --stdout         * Write files to stdout
  -v, --verbose        * Make a lot of noise
  -q, --quiet          * Tighter output; suppress warnings
  -C, --nocolor        * Don't output color
  -h, --help           * Print this help and exit
  -V, --version        * Print version and exit
  


Usage: qxpak <opts> <misc args> : manipulate xpak archives

Options: -[lxcd:OvqChV]
  -l, --list           * List the contents of an archive
  -x, --extract        * Extract the contents of an archive
  -c, --create         * Create an archive of a directory/files
  -d, --dir      <arg> * Change to specified directory
  -O, --stdout         * Write files to stdout
  -v, --verbose        * Make a lot of noise
  -q, --quiet          * Tighter output; suppress warnings
  -C, --nocolor        * Don't output color
  -h, --help           * Print this help and exit
  -V, --version        * Print version and exit

#------------------------------------------------------------------------------
Usage: qatom <opts> <pkg> : split atom strings
                            拆分原子字符串
Options: -[cvqChV]
  -c, --compare        * Compare two atoms     
                       * 比较两个原子
  -v, --verbose        * Make a lot of noise 
  -q, --quiet          * Tighter output; suppress warnings
  -C, --nocolor        * Don't output color
  -h, --help           * Print this help and exit
  -V, --version        * Print version and exit

#------------------------------------------------------------------------------
Usage: qgrep <opts> <misc args> : grep in ebuilds
Options: -[IiHNclLexJEsS:B:A:vqChV]
  -I, --invert-match   * Select non-matching lines
                       * 选择不匹配的行
  -i, --ignore-case    * Ignore case distinctions
                       * 忽略大小分
  -H, --with-filename  * Print the filename for each match
                       * 打印每个匹配的文件名
  -N, --with-name      * Print the package or eclass name for each match
                       * 打印每个匹配的包名或eclass名
  -c, --count          * Only print a count of matching lines per FILE
                       * 只显示每个文件匹配行总个数
  -l, --list           * Only print FILE names containing matches
                       * 只打印文件名里面包含的匹配
  -L, --invert-list    * Only print FILE names containing no match
                       * 只打印文件名里面不匹配的内容
  -e, --regexp         * Use PATTERN as a regular expression
                       * 使用正则表达式
  -x, --extended       * Use PATTERN as an extended regular expression
                       * 使用正则表达式的扩展语法
  -J, --installed      * Search in installed ebuilds instead of the tree
                       * 搜索已安装的ebuilds
  -E, --eclass         * Search in eclasses instead of ebuilds
                       * 搜索
  -s, --skip-comments  * Skip comments lines
                       * 跳过注释行 只要重要的信息
  -S, --skip     <arg> * Skip lines matching <arg>
                       * 跳过匹配<arg>的行
  -B, --before   <arg> * Print <arg> lines of leading context
                       * 打印
  -A, --after    <arg> * Print <arg> lines of trailing context
  -v, --verbose        * Make a lot of noise
  -q, --quiet          * Tighter output; suppress warnings
  -C, --nocolor        * Don't output color
  -h, --help           * Print this help and exit
  -V, --version        * Print version and exit

#------------------------------------------------------------------------------
Usage: qmerge <opts> <pkgnames> : fetch and merge binary package

Options: -[fFsKUpuyO5vqChV]
  -f, --fetch          * Fetch package and newest Packages metadata
                       * 获取包和最新的包metadata,等同emerge -f
  -F, --force          * Fetch package (skipping Packages)
                       * 获取包 (跳过包)
  -s, --search         * Search available packages
                       * 搜过有效包
  -K, --install        * Install package
                       * 安装包
  -U, --unmerge        * Uninstall package
                       * 卸载包
  -p, --pretend        * Pretend only
                       * 假打
  -u, --update         * Update only
                       * 仅更新
  -y, --yes            * Don't prompt before overwriting
                       * 直接代替你输入yes
  -O, --nodeps         * Don't merge dependencies
                       * 不emerge依赖包
  -5, --nomd5          * Don't verify MD5 digest of files
                       * 不校验文件的MD5信息
  -v, --verbose        * Make a lot of noise
  -q, --quiet          * Tighter output; suppress warnings
  -C, --nocolor        * Don't output color
  -h, --help           * Print this help and exit
  -V, --version        * Print version and exit
#------------------------------------------------------------------------------
Usage: qsearch <opts> <regex> : search pkgname/desc

Options: -[acsSNHvqChV]
  -a, --all            * List the descriptions of every package in the cache
                       * 显示cache中每个包的描述信息
  -c, --cache          * Use the portage cache
                       * 使用portage cache
  -s, --search         * Regex search package basenames
                       * 用正则表达式搜索包的基本名字
  -S, --desc     <arg> * Regex search package descriptions
                       * 用正则表达式搜索包的基本描述信息
  -N, --name-only      * Only show package name
                       * 只显示包名
  -H, --homepage       * Show homepage info
                       * 显示主页信息
  -v, --verbose        * Make a lot of noise
                       * 详细
  -q, --quiet          * Tighter output; suppress warnings
  -C, --nocolor        * Don't output color
  -h, --help           * Print this help and exit
  -V, --version        * Print version and exit

#------------------------------------------------------------------------------
Usage: qcache <opts> <action> <args> : search the metadata cache

Options: -[p:c:idtansvqChV]
  -p, --matchpkg <arg> * match pkgname
                       * 匹配包名
  -c, --matchcat <arg> * match catname
                       * 匹配
  -i, --imlate         * list packages that can be marked stable on a given arch
                       * 显示可以
  -d, --dropped        * list packages that have dropped keywords on a version bump on a given arch
                       * 
  -t, --testing        * list packages that have ~arch versions, but no stable versions on a given arch
                       *
  -s, --stats          * display statistics about the portage tree
  -a, --all            * list packages that have at least one version keyworded for on a given arch
                       * 
  -n, --not            * list packages that aren't keyworded on a given arch.
                       *
  -v, --verbose        * Make a lot of noise
  -q, --quiet          * Tighter output; suppress warnings
  -C, --nocolor        * Don't output color
  -h, --help           * Print this help and exit
  -V, --version        * Print version and exit

#------------------------------------------------------------------------------

www.linuxsir.org/bbs/thread312978.html

//---------------------------------------------------------------
//---------------------------------------------------------------
eix_tag
update-eix-remote update 可以查到未下载的overlay里的东西
equery uses XXX    查询XXX包带的USE标志
equery hasuse X    查询使用X这个USE标志的包
eix -2 -I --only-names 查slot
eix -1 -I --only-names 
eix -U(--use) ithread 查询USE为ithread的包 
eix -v(--verbose)    详细查询

eix -l( --versionlines )  每个版本都以行列出
eix -c(--compact) 只列出一些信息

eix -d , --dup-packages  只匹配duplicated的包 如果sys-foo/bar同时存在不同
的overlay里面(包括官方portage)

eix -D, --dup-versions  同时在存不同的版本,类似-d
eix -P,--provide i.e "virtual/blackbox"

eix --only-names 只列出名字
eix -I(--installed) 列出已完装的
eix -i(--multi-installed)
eix -u(--upgrade, --upgrade+, --upgrade-) 升级
eix --stable    至少有一个是稳定版的包
eix --system 列出是system的包
eix -O, --overlay             到少匹配一个包版本在Overaly里的包
eix --in-overlay overlay_name 列出在overlay_name里的包(注:不能加overlay_name不知为何)
eix --only-in-overlay overlay_name
eix -J(--installed-overlay)  安装了overaly的包
eix --installed-from-overlay overlay

eix -s, --name 默认以名字查询
eix -S, --description 以描述查询
eix -C, --category  i.e. "app-portage"
eix -A, --category-name  i.e. "app-portage/eix"
eix -H, --homepage   i.e "http://xxx"
eix -L, --license    i.e "GPL-2"
eix --installed-with-use  安装包带use参数的
eix --installed-without-use
eix -e, --exact  直接查完整包名 如 eix -e gcc 查出只是gcc的包
eix -f, --fuzzy 模糊查找
eix -p, --pattern 
eix -r, --regex 正规表达式

eix -I -J  列出已安装的overlay的包
eix --fetch  列出最后一个版本是需要自己手动下载的包
eix --mirror 列出最后一个版本是 !m 的包
//-------------------------
 x11-themes/thinkeramik
     Available versions:  3.2.1!m {debug elibc_FreeBSD xine                                                                   rama}
     Homepage:            http://www.kde-look.org/content/s                                                                   how.php?content=10919
     De
--------------------------------------
eix --stable 列出最后一个版本为stable的包
eix --upgrade, --upgrade+, --upgrade- 最后一个版本为可升级的或是降级+ - 表示LOCAL_PORTAGE_CONFIG的真和假
eix --testing, --testing+,--testing-
eix --non-masked, --non-masked+, --non-masked-
eix --system, --system+, --system-
eix -O, --overlay 只列出包最后一个版本在overlay,无论是否安装,注意跟-J的区别
eix -T, --test-obsolete 测试陈旧的包
eix -l, --pipe 
eix -!, --not  


非常有用的FORMAT
   Application:
       FORMAT='{downgrade}%{FORMAT_COMPACT}{}' eix -I
              This  will  print  all installed packages for which there are downgrade recommendations.  Note that
              the compact format is used to output the packages: We  cannot  use  FORMAT='{downgrade}%{FORMAT}{}'
              because  this  would be a self-reference.  However, if you want to use the default FORMAT layout to
              output the packages, we can use FORMAT_COMPACT to wrap around FORMAT:

       FORMAT_COMPACT='{downgrade}%{FORMAT}{}' eix -cI
              This is as above, but the matching packages will be printed with the default (non-compact)  format.
              The  option  -c  is  needed  so  that eix will use our FORMAT_COMPACT variable as the format string
              (which we "misused" as a "wrapper" for FORMAT in this example).
//---------------------------------------------------------------

www.linuxsir.org/bbs/thread311868.html

视频转换

每次用都要上网搜,在这里记一下

参见www.cicw.org/cms/html/28/t-2028.html

mencoder


制作适合在智能手机和PDA上观看的mpeg4视频。
Linux上有一个很强大的视频音频转换软件,就是Mplayer自带的mencoder (MPlayer's Movie Encoder)。mencoder就象是一台全手动的照相机,可调整的选项非常多,不过这儿只是把最常见的情况说一下。

转换avi文件,并把字幕内嵌到视频中。首先假设一下下列的条件:
文件名:video.avi
字幕文件名:video.srt
目标文件:new.avi
目标文件格式:mpeg4
目标文件视频码率:200
目标文件音频码率:64
目标文件分辨率: 320:240
制作内嵌字幕所需的字体:simsun.ttf
(上面各项都可以根据实际情况进行调整)
转换命令如下:

mencoder -oac mp3lame -lameopts vbr=3:br=64 -ovc lavc -lavcopts vcodec=mpeg4:mbd=1:vbitrate=200 -sub video.srt -o new.avi -font simsun.ttf video.avi -subcp cp936 -subfont-text-scale 4 -vf scale=320:240


各选项的含义:
-oac 编码文件的音频部分。这儿是用lame将音频encode成mp3,即mp3lame。其他可用的选项可以调用mencoder的man page查看。
-lameopts 顾名思义,即lame选项,这儿只需定义一下码率就可以了。
vbr 设定音频码率的方法,格式为vbr=<0-4>

0 cbr average bitrate
1 mt
2 rh   constant bitrate Also forces CBR mode encoding on subsequent ABR presets modes.
3 abr
4 mtrh

在这儿用的是3,abr。
br 就是设定我们所需要的码率值,格式为br=<0-1024>,只能在vbr为0和3的情况下才能使用该选项。
-ovc 编码文件的视频部分。主要有以下几个选项

-ovc copy
      不进行编码,只是复制视频流
-ovc divx4
      编码成DivX4/DivX5
-ovc raw
                        编码成任意不压缩的格式(用‘-vf format’设定具体的格式)
-ovc lavc
      使用libavcodec进行编码

-lavcopts 就是libavcodec的选项。
vcodec=使用指定的视频编码,下面列一下几个主要的值

h264
  H.264
h263
  H.263
h263p
  H.263+
mpeg4
  MPEG-4 (DivX 4/5)
msmpeg4
  DivX 3
msmpeg4v2
  MS MPEG4v2
wmv1
  Windows Media Video, version 1 (又称 WMV7)
wmv2
  Windows Media Video, version 2 (又称 WMV8)
rv10
  旧的RealVideo格式
mpeg1video
  MPEG-1 video
mpeg2video
  MPEG-2 video

mbd 决定视频宏块的算法,这儿只需要mbd=1即可。其余的可以查看man page。
vbitrate 设定视频的码率(默认为800)。
-sub 设定字幕文件
-o 目标视频文件
-font 制作内嵌字幕所需字体的路径
-subcp 字幕的编码,简体中文就是cp936
-subfont-text-scale 字幕字体的大小
-vf scale 视频的分辨率
如果不需要将字幕内嵌入视频文件,只需要去掉-sub、-font、-subcp、-subfont-text-scale这几个选项。将rmvb转换成mpeg4也是如此。

对于16:9比例的宽频视频文件,按照上面的方法转换会把人挤扁,可以通过加黑边的方式解决,
就是在转换好的视频上下加上黑边,补足4:3(320:240)这样需要将最开始的参数中的-vf-add scale=320:240改为-vf-add scale=320:-3,expand=:240:::1,意思就是宽度保持不变,高度用黑边补足


ffmpeg


格式:ffmpeg [[输入文件选项]- i 输入文件名] {[输入文件选项] 输出文件名}
主要选项:
-L             显示ffmpeg的版权说明
-h             显示帮助
-version         显示版本
-formats         显示支持的文件格式,编码和协议
-f 格式名                     强制使用格式
-img 文件格式名             强制使用片格式
-i 文件名                     待转换文件名字
-y             覆盖同名输出文件
-t 时间                         设置影片时间长度
-fs 最大尺寸                 设置文件的最大尺寸
-ss 时间点     设置开始转换的时间点
-title 文字     设置标题
-author 文字   设置作者
-copyright 文字   设置版权声明
-comment 文字   设置备注

视频选项:
-b 比特率       设置文件比特率 (单位是kbit/s)
-r 速度         桢速度 (Hz value)
-s 大小         设置大小,宽乘高
-newvideo       在现在的视频流后面加入信的视频流

Audio options:
-aframes 数字     设置转换多少桢(frame)的音频
-ab bitrate       设置音乐的比特率(单位:kbit/s)
-aq 质量       这只音频质量 (指定编码)
-ar 采样率         设置音频采样率 (单位:Hz)
-ac 声道数字     设置声道数
-an           取消音频
-acodec 编码     强制音频 编码 ('copy' to copy stream)
-vol volume       改变音量 (256为普通)
-newaudio       追加音乐

调整分区

根目录快满了,今天将从/home分出5G给/usr/portage,并换成了ReiserFS,小记一下。

主要参考了这篇文章www.cublog.cn/u/13991/showart_138823.html感谢~

1、

df

 

/dev/hda6              20G   12G  2.6G  60% /home

2、

sudo fdisk -l

记录/dev/hda6的起始柱面s,结束柱面e1,unit值。

3、计算调整后hda6的终止柱面号e2 = s+[(15*1024*1024*1024)/unit],15为调整后为15G

4、一些准备工作:
重新编译内核加入ReiserFS支持。

emerge reiserfsprogs



5、重启进入单用户模式 init 1 ,现在正式开始

6、检查文件系统

fsck.ext3 /dev/hda6



7、去除ext3文件系统的日志

tune2fs -O ^has_journal /dev/hda6



8、调整文件系统大小

resize2fs /dev/hda6 15G



9、再加上日志

tune2fs -j /dev/hda9



10、再次检查文件系统

fsck.ext3 /dev/hda6



11、用fdisk分区

fdisk /dev/hda


进入后用d删掉hda6。新建分区,起始柱面为s,结束柱面为e2,为hda9。新建分区,起始为e2+1,结束为e1,为/hda10。用w保存退出。

12、格式化新分区

mkfs.reiserfs /dev/hda10



13、修改/etc/fstab,将原来的hda6改为hda10,新加一行
/dev/hda10    /usr/portage    reiserfs    noatime        0 2

14、将/dev/hda10挂到/media上,将原来/usr/portage中的所有东西移到/media/下面。

16、重启,一切ok

注:没有做备份,/home太大了有12G,没地方放。