软件是对质量的不懈追求

#

vim 的一些高级用法

说明:如果你准备把本文中的命令放到配置文件(比如 .vimrc)中而不是在命令行执行,那么请去掉开头的冒号。

★ 键映射

:maptype key command

其中,key 是要映射的键(序列),command 是所要映射的命令,maptype 包括如下几种:

map  命令,可视和命令追加模式下的键映射

vmap 可视模式下的键映射

nmap 命令模式下的键映射

omap 命令追加模式下的键映射

map! 插入和命令行模式下的键映射

imap 插入模式下的键映射

cmap 命令行模式下的键映射

说明:命令追加模式指的是命令输入中的状态,也就是在输入一个需要多个按键的命令时,已经开始输入但未完成的状态。

举个例子,

:map <F2> gg

的意思是在命令,可视和命令追加模式把 F2 键映射为命令 gg,也就是说,当在这三种模式下时,按下 F2 键,就相当于按下了键序列 gg,其作用是定位到第一行。

要想避免 vim 把你映射的 command 中的内容再次映射的话,应该使用 noremap,其格式与 map 时相同。这时候,上面的各种 maptype 分别对应如下:

noremap  命令,可视和命令追加模式下的键映射(无二次映射的)

vnoremap 可视模式下的键映射(无二次映射的)

nnoremap 命令模式下的键映射(无二次映射的)

onoremap 命令追加模式下的键映射(无二次映射的)

noremap! 插入和命令行模式下的键映射(无二次映射的)

inoremap 插入模式下的键映射(无二次映射的)

cnoremap 命令行模式下的键映射(无二次映射的)

取消一个键映射用 unmap,格式为 unmap key。其中 key 为之前定义了映射的键,unmap 可以换为如下几种之一:

unmap  取消命令,可视和命令追加模式下的键映射

vunmap 取消可视模式下的键映射

nunmap 取消命令模式下的键映射

ounmap 取消命令追加模式下的键映射

unmap! 取消插入和命令行模式下的键映射

iunmap 取消插入模式下的键映射

cunmap 取消命令行模式下的键映射

★ 把当前目录设为正在编辑的文件所在的目录

:cd %:p:h

说明:只在类 Unix 操作系统下可用。

:lcd %:p:h

说明:在所有操作系统下可用。

★ 打开文件的时候自动将当前目录设为该文件所在的目录

在 .vimrc 中加入如下行:

:au BufEnter * :cd! %:p:h

★ 转换文件格式

由于 Unix、Window 和 MacOS 的换行符的内部表示不一样,因此有时候需要转换文件格式。

将文件格式转换为 Unix 格式:

:set fileformat=unix

将文件格式转换为 Windows 格式:

:set fileformat=dos

★ 让 gvim 启动时窗口最大化(只在 Windows 下可用)

在 _vimrc 中加入如下行

autocmd GUIEnter * simalt ~x

posted @ 2009-11-14 14:08 BlakeSu 阅读(278) | 评论 (0)编辑 收藏

Struts2 实现格式化日期、小数

首先说说格式化日期。strtus2有提供一个<s:date/>来格式化日期,
    例:<s:date value =Date" format="yyyy-MM-dd" />
这样可保证在不同的游览器中都显示为“2007-11-03”的格式。但这只能实现普通显示,如果要使用编辑组件呢?有两种简便方法:
    1、使用struts2的dojo组件,<s:dateteimpicker/>
    例:<s:datetimepicker name="Date" displayFormat="yyyy-MM-dd" />
    2、使用JSTL
    例:<s:textfield name="" value="${}" />
  
    再说说格式化小数。Sturts2没有象JSTL一样提供一个<c:fmt>的格化式标签,所以要实现格式化比较麻烦一点。利用i18n与text来自定义实现小数格式化。
    例:首先在class目录下创建一个Format.properties资源文件,
        输入 FormatNumeral={0,number,##.000}
        然后在页面引入这个定义。
<s:i18n name="Format">
   <s:text name="FormatNumeral" >

       <s:param value="aNumeral"/>

    </s:text>
</s:i18n>
 

    利用这个例子,还可以自定义多种格式化方式,相当灵活了。

posted @ 2009-11-14 14:07 BlakeSu 阅读(731) | 评论 (0)编辑 收藏

最有用的几个Firefox使用技巧

  • 更多的网页空间:除了使用F11通过全屏阅读外,你还可以通过缩小Firefox工具条图标的大小:右击工具条 -> 定制 -> 使用小图标。
  • 快捷键:
    • Ctrl + F (查找)
    • Alt + N (查找下一个)
    • Ctrl + D (加入书签)
    • Ctrl + T (新标签页)
    • Ctrl + K (到搜索栏)
    • Ctrl + L (到地址栏)
    • Ctrl + = (增大字体)
    • Ctrl + - (缩小字体)
    • Ctrl + W (关闭当前页)
    • F5 (刷新)
    • Alt-Home (主页)
  • 自动完成:在地址栏(Ctrl + L),通过 Ctrl + Enter 自动加入“www.”和“.com”;通过 Shift + Enter 自动加入“www.”和“.net”
  • 标签切换:与其用鼠标点击,不如用键盘来帮助你呀~
    • Ctrl+Tab (从左往右切换标签)
    • Ctrl+Shft+Tab (反方向切换标签)
    • Ctrl+1-9 (切换到特定一个标签)
  • 删除某一条URL记录:到地址栏(Ctrl + L),选择你想删除的地址,“Delete”就可以了。
  • about:config:请参阅《About:config Tips and Screenshots》。
  • 限制Firefox的内存使用率:在地址栏(Ctrl + L)中输入about:config,找到“browser.cache”,然后选择“browser.cache.memory.capacity”。 原值为50000,但是你可以设置得更小。如果你的内存大小在512MB到1GB之间,建议设定为15000。
  • 最大限度的减少内存使用率:Firefox最小化时可以减少内存占有率。在地址栏(Ctrl + L)中输入about:config,新建一个Boolean,为“config.trim_on_minimize”,然后设置为“true”。重新启动Firefox后才会有效果。

posted @ 2009-11-14 14:04 BlakeSu 阅读(190) | 评论 (0)编辑 收藏

Spring 框架的优点及缺点

首先Spring 是一个框架,使用Spring并不代表代码质量的提高,就像盖房子选择用上海的地皮还是北京的地皮一样,房子质量与土地所在的城市无关,与房子的具体设计方案和选料有关。
使用Spring 等框架可以简化很多基础性的工作,配置好后可以方便构建业务应用。

框 架使用多了会有局限的感觉,像小鸟被套在笼子里,无法飞出去,虽然在笼子里面吃喝不愁。目前编程的门槛越来越低,诸多开源框架广泛传播,几乎没有什么技术 门槛,会配置就会编程,而一个好的DBA对软件性能会有很大提高,软件的核心逻辑最终会转移到对数据库的操作上,而且对目前从事的工作来讲,感觉技术的瓶 颈越来越多的局限在对数据库的操作上,下一步要认真提高下了。

Spring的优势不言而喻:

1. 提供了一种管理对象的方法,可以把中间层对象有效地组织起来。一个完美的框架“黏合剂”。

2. 采用了分层结构,可以增量引入到项目中。

3. 有利于面向接口编程习惯的养成。

4. 目的之一是为了写出易于测试的代码。

5. 非侵入性,应用程序对Spring API的依赖可以减至最小限度。

6. 一致的数据访问介面。

6. 一个轻量级的架构解决方案。

对Spring的理解

Spring致力于使用POJOs来构建应用程序。由框架提供应用程序的基础设施,将只含有业务逻辑的POJOs作为组件来管理。从而在应用程序中形成两条相对独立发展的平行线,并且在各自的抽象层面上延长了各自的生命周期。

Spring的工作基础是Ioc。Ioc将创建对象的职责从应用程序代码剥离到了框架中,通常2中注入方式:setter 和 ctor参数。

每个Bean定义被当作一个POJO(通过类名和JavaBean的初始属性或构造方法参数两种方式定义的Bean)。

Spring的核心在org.springframework.beans,更高抽象层面是BeanFactory. BeanFactory是一个非常轻量级的容器。

关于可维护性的思考

Spring之类的技术确实带来了应用系统的可维护性的提高吗?

Ioc, AOP之类的技术,本质上都是将原本位于应用程序代码中"硬编码"逻辑,剥离出来放到了配置文件中(或者其他形式)。主流声音都是认为提高了应用程序的可维护性。

但如果从以下方面观察,结合项目实际经验,个人感觉这些技术的应用大大降低了应用程序的可维护性,尤其是面对一个陌生的系统,或者项目人员变动频繁的时候。

  1. 中断了应用程序的逻辑,使代码变得不完整,不直观。此时单从Source无法完全把握应用的所有行为。

  2. 将原本应该代码化的逻辑配置化,增加了出错的机会以及额外的负担。

  3. 时光倒退,失去了IDE的支持。在目前IDE功能日益强大的时代,以往代码重构等让人头痛的举动越来越容易。而且IDE还提供了诸多强大的辅助功能,使得编程的门槛降低很多。通常来说,维护代码要比维护配置文件,或者配置文件+代码的混合体要容易的多。

  4. 调试阶段不直观,后期的bug对应阶段,不容易判断问题所在。

posted @ 2009-11-14 14:01 BlakeSu 阅读(214) | 评论 (0)编辑 收藏

Linux Remote X应用

假设本地主机ip为172.16.1.1,远程的主机ip为172.16.1.2

  第一步,在本地主机上的任意一个xterm中执行xhost,用来允许远程的其它主机可以和本地主机的X server联网:

  xhost + 172.16.1.2

  如果不指定任何ip地址,则表示权限完全放开,这会带来安全问题,要小心!

  第二步,确认本地主机的xfs是运行的.用ps检查一下进程.

  第三步,从本地主机(172.16.1.1)上通过网络登录到远程主机172.16.1.2上,你用telnet,ssh,rsh都可以.设置DISPLAY变量.

  export DISPLAY=172.16.1.1:0

  第四步,现在可以使用远程主机上的X 应用程序了.

  这么样,很方便吧,但是你还不能掌控整个桌面环境,这个工作就交给vnc吧!Remote X 在局域网上运行效果很不错,普通的电话拨号就不用试了,速度太慢了.

posted @ 2009-11-14 13:56 BlakeSu 阅读(252) | 评论 (0)编辑 收藏

VNC配置

我相信有不少人在windows环境用过pcanywhere,但你想不想用一个免费的,可以在linux,win9x/nt上都可以使用的pcanywhere,这就是vnc.

  vnc就是vitual network computing的缩写,它支持许多操作平台,甚至可在浏览器中操作.

  我主要介绍vncviewer的用法,以及用linux远程控制linux或nt.

  vnc client通过架构在tcp/ip上的vnc协议与vnc server沟通,通过认证后,把X server的桌面环境,输入设备,和X 资源交给vncserver掌控,vnc server将桌面环境通过vnc 协议送给vnc client端.让vnc client来操纵vnc server桌面环境和输入设备.

  首先下载到vnc的linux版本和windows版本.

  当前的linux版本是vnc-3.3.3r1_x86_linux_2.0.tgz

  当前的windows版本是vnc-3.3.3r7_x86_win32.zip

  1.安装linux版的vnc

  (1)安装

  tar zxvf vnc-3.3.3r1_x86_linux_2.0.tgz

  cd vnc_x86_linux_2.0

  cp *vnc* /usr/local/bin/

  mkdir /usr/local/vnc

  cp -r classes/ /usr/local/vnc/

  (2)设置vnc server的访问密码

  vncpasswd

  (3)启动vnc server

  vncserver

  注意运行后显示的信息,记下所用的端口号,一般从1开始,因为0被x server占用了.现在,你就能提供vnc服务了.vnc client的用法等会介绍.

  2、安装nt版的vnc

  1)安装

  解开vnc-3.3.3r7_x86_win32.zip包后,会产生winvnc和vncviewer两个目录.winvnc目录中是vnc server的安装程序,vncviewer目录中是vnc client的安装序.我只关心vnc server,在winvnc目录中执行setup即可.

  2)设置

  首先执行install default registry settings.

  run winvnc(app mode)就是执行vnc server

  这时可看到winvnc运行的小图标,用鼠标右键点击图标,在properties/incoming connections中设定密码.默认配置即可.

  现在,你的nt就能提供vnc服务了.

  3、使用vncviewer

  vnc server启动成功后,你就可用vncviewer来远程控制桌面了.

  vncviewer xxx.xxx.xxx.xxx:display number

  例如,vncviewer 172.16.1.2:1

  按要求输入密码就可以看到远程的桌面了.

  注意:viewers需要在16位色的显示模式下工作,如果您的操作系统中没上16位色,那么请您及时的调整您计算机的显示模式。不然vncviewer无法正常工作。

  4、linux版vnc server的改进.

  linux上的vnc server内定的桌面管理环境是twm,实在是太简陋了.

  修改$HOME/.vnc/xstartup这个文件.

  把所有内容的行前加上#,再在接尾部份加上:

  startkde &

  你当然可用你喜好的桌面代替.我这是用kde来代替twm,速度会慢少少,但用起来方便不少.

  注意要重新启动vnc server.

  5、通过浏览器使用vnc

  通过浏览器使用vnc,要注意端口号的变化.

  假设vnc server是172.16.1.2:1的话,那么,可用浏览器访问http://172.16.1.2:5801

  端口号=display number + 5800

  好了,心动不如行动,just do it !

posted @ 2009-11-14 13:55 BlakeSu 阅读(263) | 评论 (0)编辑 收藏

Undoing in Git - Reset and Revert

If you've messed up the working tree, but haven't yet committed your mistake, you can return the entire working tree to the last committed state with

$ git reset --hard HEAD

If you make a commit that you later wish you hadn't, there are two fundamentally different ways to fix the problem:

  1. You can create a new commit that undoes whatever was done by the old commit. This is the correct thing if your mistake has already been made public.

  2. You can go back and modify the old commit. You should never do this if you have already made the history public; git does not normally expect the "history" of a project to change, and cannot correctly perform repeated merges from a branch that has had its history changed.

Fixing a mistake with a new commit

Creating a new commit that reverts an earlier change is very easy; just pass the git revert command a reference to the bad commit; for example, to revert the most recent commit:

$ git revert HEAD

This will create a new commit which undoes the change in HEAD. You will be given a chance to edit the commit message for the new commit.

You can also revert an earlier change, for example, the next-to-last:

$ git revert HEAD^

In this case git will attempt to undo the old change while leaving intact any changes made since then. If more recent changes overlap with the changes to be reverted, then you will be asked to fix conflicts manually, just as in the case of <<resolving-a-merge, resolving a merge>>.

posted @ 2009-11-14 13:53 BlakeSu 阅读(409) | 评论 (0)编辑 收藏

Tutorial: The best tips & tricks for bash

The bash shell is just amazing. There are so many tasks that can be simplified using its handy features. This tutorial tells about some of those features, explains what exactly they do and learns you how to use them.

Difficulty: Basic - Medium 

Running a command from your history

Sometimes you know that you ran a command a while ago and you want to run it again. You know a bit of the command, but you don't exactly know all options, or when you executed the command. Of course, you could just keep pressing the Up Arrow until you encounter the command again, but there is a better way. You can search the bash history in an interactive mode by pressing Ctrl + r. This will put bash in history mode, allowing you to type a part of the command you're looking for. In the meanwhile, it will show the most recent occasion where the string you're typing was used. If it is showing you a too recent command, you can go further back in history by pressing Ctrl + r again and again. Once you found the command you were looking for, press enter to run it. If you can't find what you're looking for and you want to try it again or if you want to get out of history mode for an other reason, just press Ctrl + c. By the way, Ctrl + c can be used in many other cases to cancel the current operation and/or start with a fresh new line.

Repeating an argument

You can repeat the last argument of the previous command in multiple ways. Have a look at this example:

[rechosen@localhost ~]$ mkdir /path/to/exampledir 
[rechosen@localhost ~]$ cd !$

The second command might look a little strange, but it will just cd to /path/to/exampledir. The "!$" syntax repeats the last argument of the previous command. You can also insert the last argument of the previous command on the fly, which enables you to edit it before executing the command. The keyboard shortcut for this functionality is Esc + . (a period). You can also repeatedly press these keys to get the last argument of commands before the previous one.

Some keyboard shortcuts for editing

There are some pretty useful keyboard shortcuts for editing in bash. They might appear familiar to Emacs users:

  • Ctrl + a => Return to the start of the command you're typing
  • Ctrl + e => Go to the end of the command you're typing
  • Ctrl + u => Cut everything before the cursor to a special clipboard
  • Ctrl + k => Cut everything after the cursor to a special clipboard
  • Ctrl + y => Paste from the special clipboard that Ctrl + u and Ctrl + k save their data to
  • Ctrl + t => Swap the two characters before the cursor (you can actually use this to transport a character from the left to the right, try it!)
  • Ctrl + w => Delete the word / argument left of the cursor
  • Ctrl + l => Clear the screen

Dealing with jobs

If you've just started a huge process (like backupping a lot of files) using an ssh terminal and you suddenly remember that you need to do something else on the same server, you might want to get the huge process to the background. You can do this by pressing Ctrl + z, which will suspend the process, and then executing the bg command:

[rechosen@localhost ~]$ bg
[1]+ hugeprocess &

This will make the huge process continue happily in the background, allowing you to do what you need to do. If you want to background another process with the huge one still running, just use the same steps. And if you want to get a process back to the foreground again, execute fg:

[rechosen@localhost ~]$ fg
hugeprocess

But what if you want to foreground an older process that's still running? In a case like that, use the jobs command to see which processes bash is managing:

[rechosen@localhost ~]$ jobs
[1]-  Running                 hugeprocess &
[2]+  Running                 anotherprocess &

Note: A "+" after the job id means that that job is the 'current job', the one that will be affected if bg or fg is executed without any arguments. A "-" after the job id means that that job is the 'previous job'. You can refer to the previous job with "%-".

Use the job id (the number on the left), preceded by a "%", to specify which process to foreground / background, like this:

[rechosen@localhost ~]$ fg %3

And:

[rechosen@localhost ~]$ bg %7

The above snippets would foreground job [3] and background job [7]. 

Using several ways of substitution

There are multiple ways to embed a command in an other one. You could use the following way (which is called command substitution):

[rechosen@localhost ~]$ du -h -a -c $(find . -name *.conf 2>&-)

The above command is quite a mouthful of options and syntax, so I'll explain it.

  • The du command calculates the actual size of files. The -h option makes du print the sizes in human-readable format, the -a tells du to calculate the size of all files, and the -c option tells du to produce a grand total. So, "du -h -a -c" will show the sizes of all files passed to it in a human-readable form and it will produce a grand total.
  • As you might have guessed, "$(find . -name *.conf 2>&-)" takes care of giving du some files to calculate the sizes of. This part is wrapped between "$(" and ")" to tell bash that it should run the command and return the command's output (in this case as an argument for du). The find command searches for files named <can be anything>.conf in the current directory and all accessible subdirectories. The "." indicates the current directory, the -name option allows to specify the filename of the file to search for, and "*.conf" is an expression that matches any string ending with the character sequence ".conf".
  • The only thing left to explain is the "2>&-". This part of the syntax makes bash discard the errors that find produces, so du won't get any non-filename input. There is a huge amount of explanation about this syntax near the end of the tutorial (look for "2>&1" and further).

And there's another way to substitute, called process substitution:

[rechosen@localhost ~]$ diff <(ps axo comm) <(ssh user@host ps axo comm)

The command in the snippet above will compare the running processes on the local system and a remote system with an ssh server. Let's have a closer look at it:

  • First of all, diff. The diff command can be used to compare two files. I won't tell much about it here, as there is an extensive tutorial about diff and patch on this site.
  • Next, the "<(" and ")". These strings indicate that bash should substitute the command between them as a process. This will create a named pipe (usually in /dev/fd) that, in our case, will be given to diff as a file to compare.
  • Now the "ps axo comm". The ps command is used to list processes currently running on the system. The "a" option tells ps to list all processes with a tty, the "x" tells ps to list processes without a tty, too, and "o comm" tells ps to list the commands only ("o" indicates the starting of a user-defined output declaration, and "comm" indicates that ps should print the COMMAND column).
  • The "ssh user@host ps axo comm" will run "ps axo comm" on a remote system with an ssh server. For more detailed information about ssh, see this site's tutorial about ssh and scp.

Let's have a look at the whole snippet now:

  • After interpreting the line, bash will run "ps axo comm" and redirect the output to a named pipe,
  • then it will execute "ssh user@host ps axo comm" and redirect the output to another named pipe,
  • and then it will execute diff with the filenames of the named pipes as argument.
  • The diff command will read the output from the pipes and compare them, and return the differences to the terminal so you can quickly see what differences there are in running processes (if you're familiar with diff's output, that is).

This way, you have done in one line what would normally require at least two: comparing the outputs of two processes.

And there even is another way, called xargs. This command can feed arguments, usually imported through a pipe, to a command. See the next chapter for more information about pipes. We'll now focus on xargs itself. Have a look at this example:

[rechosen@localhost ~]$ find . -name *.conf -print0 | xargs -0 grep -l -Z mem_limit | xargs -0 -i cp {} {}.bak

Note: the "-l" after grep is an L, not an i. 

The command in the snippet above will make a backup of all .conf files in the current directory and accessible subdirectories that contain the string "mem_limit".

  • The find command is used to find all files in the current directory (the ".") and accessible subdirectories with a filename (the "-name" option) that ends with ".conf" ("*.conf" means "<anything>.conf"). It returns a list of them, with null characters as separators ("-print0" tells find to do so).
  • The output of find is piped (the "|" operator, see the next chapter for more information) to xargs. The "-0" option tells xargs that the names are separated by null characters, and "grep -l -Z mem_limit" is the command that the list of files will be feeded to as arguments. The grep command will search the files it gets from xargs for the string "mem_limit", returning a list of files (the -l option tells grep not to return the contents of the files, but just the filenames), again separated by null characters (the "-Z" option causes grep to do this).
  • The output of grep is also piped, to "xargs -0 -i cp {} {}.bak". We know what xargs does, except for the "-i" option. The "-i" option tells xargs to replace every occasion of the specified string with the argument it gets through the pipe. If no string is specified (as in our case), xargs will assume that it should replace the string "{}". Next, the "cp {} {}.bak". The "{}" will be replaced by xargs with the argument, so, if xargs got the file "sample.conf" through the pipe, cp will copy the file "sample.conf" to the file "sample.conf.bak", effectively making a backup of it.

These substitutions can, once mastered, provide short and quick solutions for complicated problems.

Piping data through commands

One of the most powerful features is the ability to pipe data through commands. You could see this as letting bash take the output of a command, then feed it to an other command, take the output of that, feed it to another and so on. This is a simple example of using a pipe:

[rechosen@localhost ~]$ ps aux | grep init

If you don't know the commands yet: "ps aux" lists all processes executed by a valid user that are currently running on your system (the "a" means that processes of other users than the current user should also be listed, the "u" means that only processes executed by a valid user should be shown, and the "x" means that background processes (without a tty) should also be listed). The "grep init" searches the output of "ps aux" for the string "init". It does so because bash pipes the output of "ps aux" to "grep init", and bash does that because of the "|" operator.

The "|" operator makes bash redirect all data that the command left of it returns to the stdout (more about that later) to the stdin of the command right of it. There are a lot of commands that support taking data from the stdin, and almost every program supports returning data using the stdout.

The stdin and stdout are part of the standard streams; they were introduced with UNIX and are channels over which data can be transported. There are three standard streams (the third one is stderr, which should be used to report errors over). The stdin channel can be used by other programs to feed data to a running process, and the stdout channel can be used by a program to export data. Usually, stdout output (and stderr output, too) is received by the terminal environment in which the program is running, in our case bash. By default, bash will show you the output by echoing it onto the terminal screen, but now that we pipe it to an other command, we are not shown the data.

Please note that, as in a pipe only the stdout of the command on the left is passed on to the next one, the stderr output will still go to the terminal. I will explain how to alter this further on in this tutorial.

If you want to see the data that's passed on between programs in a pipe, you can insert the "tee" command between it. This program receives data from the stdin and then writes it to a file, while also passing it on again through the stdout. This way, if something is going wrong in a pipe sequence, you can see what data was passing through the pipes. The "tee" command is used like this:

[rechosen@localhost ~]$ ps aux | tee filename | grep init

The "grep" command will still receive the output of "ps aux", as tee just passes the data on, but you will be able to read the output of "ps aux" in the file <filename> after the commands have been executed. Note that "tee" tries to replace the file <filename> if you specify the command like this. If you don't want "tee" to replace the file but to append the data to it instead, use the -a option, like this:

[rechosen@localhost ~]$ ps aux | tee -a filename | grep init

As you have been able to see in the above command, you can place a lot of command with pipes after each other. This is not infinite, though. There is a maximum command-line length, which is usually determined by the kernel. However, this value usually is so big that you are very unlikely to hit the limit. If you do, you can always save the stdout output to a file somewhere inbetween and then use that file to continue operation. And that introduces the next subject: saving the stdout output to a file.

Saving the stdout output to a file

You can save the stdout output of a command to a file like this:

[rechosen@localhost ~]$ ps aux > filename

The above syntax will make bash write the stdout output of "ps aux" to the file filename. If filename already exists, bash will try to overwrite it. If you don't want bash to do so, but to append the output of "ps aux" to filename, you could do that this way:

[rechosen@localhost ~]$ ps aux >> filename

You can use this feature of bash to split a long line of pipes into multiple lines:

[rechosen@localhost ~]$ command1 | command2 | ... | commandN > tempfile1

[rechosen@localhost ~]$ cat tempfile1 | command1 | command2 | ... | commandN > tempfile2

And so on. Note that the above use of cat is, in most cases, a useless one. In many cases, you can let command1 in the second snippet read the file, like this:

[rechosen@localhost ~]$ command1 tempfile1 | command2 | ... | commandN > tempfile2

And in other cases, you can use a redirect to feed a file to command1:

[rechosen@localhost ~]$ command1 < tempfile1 | command2 | ... | commandN > tempfile2

To be honest, I mainly included this to avoid getting the Useless Use of Cat Award =).

Anyway, you can also use bash's ability to write streams to file for logging the output of script commands, for example. By the way, did you know that bash can also write the stderr output to a file, or both the stdout and the stderr streams?

Playing with standard streams: redirecting and combining

The bash shell allows us to redirect streams to other streams or to files. This is quite a complicated feature, so I'll try to explain it as clearly as possible. Redirecting a stream is done like this:

[rechosen@localhost ~]$ ps aux 2>&1 | grep init

In the snippet above, "grep init" will not only search the stdout output of "ps aux", but also the stderr output. The stderr and the stdout streams are combined. This is caused by that strange "2>&1" after "ps aux". Let's have a closer look at that.

First, the "2". As said, there are three standard streams (stin, stdout and stderr).These standard streams also have default numbers:

  • 0: stdin
  • 1: stdout
  • 2: sterr

As you can see, "2" is the stream number of stderr. And ">", we already know that from making bash write to a file. The actual meaning of this symbol is "redirect the stream on the left to the stream on the right". If there is no stream on the left, bash will assume you're trying to redirect stdout. If there's a filename on the right, bash will redirect the stream on the left to that file, so that everything passing through the pipe is written to the file.

Note: the ">" symbol is used with and without a space behind it in this tutorial. This is only to keep it clear whether we're redirecting to a file or to a stream: in reality, when dealing with streams, it doesn't matter whether a space is behind it or not. When substituting processes, you shouldn't use any spaces.

Back to our "2>&1". As explained, "2" is the stream number of stderr, ">" redirects the stream somewhere, but what is "&1"? You might have guessed, as the "grep init" command mentioned above searches both the stdout and stderr stream, that "&1" is the stdout stream. The "&" in front of it tells bash that you don't mean a file with filename "1". The streams are sent to the same destination, and to the command receiving them it will seem like they are combined.

If you'd want to write to a file with the name "&1", you'd have to escape the "&", like this:

[rechosen@localhost ~]$ ps aux > \&1

Or you could put "&1" between single quotes, like this:

[rechosen@localhost ~]$ ps aux > '&1'

Wrapping a filename containing problematic characters between single quotes generally is a good way to stop bash from messing with it (unless there are single quotes in the string, then you'd have have escape them by putting a \ in front of them).

Back again to the "2>&1". Now that we know what it means, we can also apply it in other ways, like this:

[rechosen@localhost ~]$ ps aux > filename 2>&1

The stdout output of ps aux will be sent to the file filename, and the stderr output, too. Now, this might seem unlogical. If bash would interpret it from the left to the right (and it does), you might think that it should be like:

[rechosen@localhost ~]$ ps aux 2>&1 > filename

Well, it shouldn't. If you'd execute the above syntax, the stderr output would just be echoed to the terminal. Why? Because bash does not redirect to a stream, but to the current final destination of the stream. Let me explain it:

  • First, we're telling bash to run the command "ps" with "aux" as an argument.
  • Then, we're telling to redirect stderr to stdout. At the moment, stdout is still going to the terminal, so the stderr output of "ps aux" is sent to the terminal.
  • After that, we're telling bash to redirect the stdout output to the file filename. The stdout output of "ps aux" is sent to this file indeed, but the stderr output isn't: it is not affected by stream 1.

If we put the redirections the other way around ("> filename" first), it does work. I'll explain that, too:

  • First, we're telling bash to run the command "ps" with "aux" as an argument (again).
  • Then, we're redirecting the stdout to the file filename. This causes the stdout output of "ps aux" to be written to that file.
  • After that, we're redirecting the stderr stream to the stdout stream. The stdout stream is still pointing to the file filename because of the former statement. Therefore, stderr output is also written to the file.

Get it? The redirects cause a stream to go to the same final destination as the specified one. It does not actually merge the streams, however.

Now that we know how to redirect, we can use it in many ways. For example, we could pipe the stderr output instead of the stdout output:

[rechosen@localhost ~]$ ps aux 2>&1 > /dev/null | grep init

The syntax in this snippet will send the stderr output of "ps aux" to "grep init", while the stdout output is sent to /dev/null and therefore discarded. Note that "grep init" will probably not find anything in this case as "ps aux" is unlikely to report any errors.

When looking more closely to the snippet above, a problem arises. As bash reads the command statements from the left to the right, nothing should go through the pipe, you might say. At the moment that "2>&1" is specified, stdout should still point to the terminal, shouldn't it? Well, here's a thing you should remember: bash reads command statements from the left to the right, but, before that, determines if there are multiple command statements and in which way they are separated. Therefore, bash already read and applied the "|" pipe symbol and stdout is already pointing to the pipe. Note that this also means that stream redirections must be specified before the pipe operator. If you, for example, would move "2>&1" to the end of the command, after "grep init", it would not affect ps aux anymore.

We can also swap the stdout and the stderr stream. This allows to let the stderr stream pass through a pipe while the stdout is printed to the terminal. This will require a 3rd stream. Let's have a look at this example:

[rechosen@localhost ~]$ ps aux 3>&1 1>&2 2>&3 | grep init

That stuff seems to be quite complicated, right? Let's analyze what we're doing here:

  • "3>&1" => We're redirecting stream 3 to the same final destination as stream 1 (stdout). Stream 3 is a non-standard stream, but it is pretty much always available in bash. This way, we're effectively making a backup of the destination of stdout, which is, in this case, the pipe.
  • "1>&2" => We're redirecting stream 1 (stdout) to the same final destination as stream 2 (stderr). This destination is the terminal.
  • "2>&3" => We're redirecting stream 2 (stderr) to the final destination of stream 3. In the first step of these three ones, we set stream 3 to the same final destination as stream 1 (stdout), which was the pipe at that moment, and after that, we redirected stream 1 (stdout) to the final destination of stream 2 at that moment, the terminal. If we wouldn't have made a backup of stream 1's final destination in the beginning, we would not be able to refer to it now.

So, by using a backup stream, we can swap the stdout and stderr stream. This backup stream does not belong to the standard streams, but it is pretty much always available in bash. If you're using it in a script, make sure you aren't breaking an earlier command by playing with the 3rd stream. You can also use stream 4, 5, 6 7 and so on if you need more streams. The highest stream number usually is 1023 (there are 1024 streams, but the first stream is stream 0, stdin). This may be different on other linux systems. Your mileage may vary. If you try to use a non-existing stream, you will get an error like this:

bash: 1: Bad file descriptor

If you want to return a non-standard stream to it's default state, redirect it to "&-", like this:

[rechosen@localhost ~]$ ps aux 3>&1 1>&2 2>&3 3>&- | grep init

Note that the stream redirections are always reset to their initial state if you're using them in a command. You'll only need to do this manually if you made a redirect using, for example, exec, as redirects made this way will last until changed manually.

Final words

Well, I hope you learned a lot from this tutorial. If the things you read here were new for you, don't worry if you can't apply them immediately. It already is useful if you just know what a statement means if you stumble upon it sometime. If you liked this, please help spreading the word about this blog by posting a link to it here and there. Thank you for reading, and good luck working with bash!

posted @ 2009-11-14 13:49 BlakeSu 阅读(189) | 评论 (0)编辑 收藏

aptitude 使用快速参考

aptitude 与 apt-get 一样,是 Debian 及其衍生系统中功能极其强大的包管理工具。与 apt-get 不同的是,aptitude 在处理依赖问题上更佳一些。举例来说,aptitude 在删除一个包时,会同时删除本身所依赖的包。这样,系统中不会残留无用的包,整个系统更为干净。以下是笔者总结的一些常用 aptitude 命令,仅供参考。

命令 作用
aptitude update 更新可用的包列表
aptitude upgrade 升级可用的包
aptitude dist-upgrade 将系统升级到新的发行版
aptitude install pkgname 安装包
aptitude remove pkgname 删除包
aptitude purge pkgname 删除包及其配置文件
aptitude search string 搜索包
aptitude show pkgname 显示包的详细信息
aptitude clean 删除下载的包文件
aptitude autoclean 仅删除过期的包文件

当然,你也可以在文本界面模式中使用 aptitude。

posted @ 2009-11-14 13:49 BlakeSu 阅读(172) | 评论 (0)编辑 收藏

linux 头文件作用(转载)

POSIX标准定义的头文件
<dirent.h>        目录项
<fcntl.h>         文件控制
<fnmatch.h>    文件名匹配类型
<glob.h>    路径名模式匹配类型
<grp.h>        组文件
<netdb.h>    网络数据库操作
<pwd.h>        口令文件
<regex.h>    正则表达式
<tar.h>        TAR归档值
<termios.h>    终端I/O
<unistd.h>    符号常量
<utime.h>    文件时间
<wordexp.h>    字符扩展类型
-------------------------
<arpa/inet.h>    INTERNET定义
<net/if.h>    套接字本地接口
<netinet/in.h>    INTERNET地址族
<netinet/tcp.h>    传输控制协议定义
-------------------------   
<sys/mman.h>    内存管理声明
<sys/select.h>    Select函数
<sys/socket.h>    套接字借口
<sys/stat.h>    文件状态
<sys/times.h>    进程时间
<sys/types.h>    基本系统数据类型
<sys/un.h>    UNIX域套接字定义
<sys/utsname.h>    系统名
<sys/wait.h>    进程控制

------------------------------
POSIX定义的XSI扩展头文件
<cpio.h>    cpio归档值   
<dlfcn.h>    动态链接
<fmtmsg.h>    消息显示结构
ftw.h>        文件树漫游
<iconv.h>    代码集转换使用程序
<langinfo.h>    语言信息常量
<libgen.h>    模式匹配函数定义
<monetary.h>    货币类型
<ndbm.h>    数据库操作
<nl_types.h>    消息类别
<poll.h>    轮询函数
<search.h>    搜索表
<strings.h>    字符串操作
<syslog.h>    系统出错日志记录
<ucontext.h>    用户上下文
<ulimit.h>    用户限制
<utmpx.h>    用户帐户数据库   
-----------------------------
<sys/ipc.h>    IPC(命名管道)
<sys/msg.h>    消息队列
<sys/resource.h>资源操作
<sys/sem.h>    信号量
<sys/shm.h>    共享存储
<sys/statvfs.h>    文件系统信息
<sys/time.h>    时间类型
<sys/timeb.h>    附加的日期和时间定义
<sys/uio.h>    矢量I/O操作

------------------------------
POSIX定义的可选头文件
<aio.h>        异步I/O
<mqueue.h>    消息队列
<pthread.h>    线程
<sched.h>    执行调度
<semaphore.h>    信号量
<spawn.h>     实时spawn接口
<stropts.h>    XSI STREAMS接口
<trace.h>     事件跟踪

posted @ 2009-11-14 13:44 BlakeSu 阅读(405) | 评论 (0)编辑 收藏

仅列出标题
共12页: First 上一页 4 5 6 7 8 9 10 11 12 下一页