Tuesday, March 17, 2009

075 使用SysRq键安全重启Linux系统

SysRq组合键是Linux的一个内核级命令,你可以通过它执行很多底层任务。比如你可以通过它从冻结状态恢复,或者重新启动系统。这个命令包括:
Alt+SysRq+commandkey:在很多系统中SysRq键就是‘Print Scr’ 键。首先你需要激活这个键。
echo "1" > /proc/sys/kernel/sysrq

SysRq组合键列表:
  • ‘k’:关闭当前虚拟控制台的所有进程。
  • ’s’:尝试同步所有加载的文件系统。
  • ‘b’:在无需卸载分区或者同步的情况下,立即重启系统。
  • ‘e’:给除了init以外所有进程发送SIGTERM
  • ‘m’:在控制台显示当前的内存信息。
  • ‘i’ :给除了init以外所有进程发送SIGKILL。
  • ‘r’:将键盘从原始模式转换到XLATE模式。
  • ’S’ :同步所有加载的文件系统。
  • ‘t’:在控制台上输出当前任何及其信息的列表。
  • ‘u’:以只读模式重新加载所有已经加载的文件系统。
  • ‘o’:立即关闭系统。
  • ‘p’ :在控制台上打印当前的注册者和标志信息。
  • ‘0-9′ :设置控制台的日志级别,从而控制哪些内核信息会打印到当前的控制台。
  • ‘f’:将调用oom_kill来关闭当前占用很多内存的进程。
  • ‘h’ :显示帮助信息。

我们也可以通过把这些信息放到/proc/sysrq-trigger 中来完成同样的事情。比如你可以执行下面的命令来重启系统。
echo "b" > /proc/sysrq-trigger

使用SysRq键安全重启Linux系统
要安全的重启一个已经挂起的Linux系统,可以这样作。这可以避免下次启动时做的fsck检查。比如按下Alt+SysRq+字母(这个字母可以是下面黑体字中的任何一个):
  • unRaw:控制键盘从X11模式返回。
  • tErminate:给每个进程发送一个SIGTERM,允许它们安全的终止。
  • kIll:发送SIGILL给所有进程,立即结束进程。
  • Sync:将数据同步到磁盘上。
  • Unmount:以只读模式重新加载所有文件系统。
  • reBoot:重新启动。

Monday, March 16, 2009

074 Crontab命令的使用

你可以通过Crontab命令在指定的日期或时间执行shell脚本或者Linux命令。必须系统管理员希望每天定时进行备份任务。
如何在cron中增加一个任务
# crontab –e
0 5 * * * /root/bin/backup.sh

它会在每天临晨五点执行 /root/bin/backup.sh
Cron字段的描述
以下是crontab文件的格式:
{minute} {hour} {day-of-month} {month} {day-of-week} {full-path-to-shell-script}

minute:允许0-59的值
hour:允许0-23的值
day-of-month:允许0-31的值
month:允许1-12的值,1代表一月,12代表十二月
Day-of-week:允许0-7的值。星期日可以是0或者7
Crontab的例子
1.在每天12:01执行任务,午夜的1分钟后。这是一个备份数据的好时候。
1 0 * * * /root/bin/backup.sh

2.在每个工作日的下午11:59进行备份
59 11 * * 1,2,3,4,5 /root/bin/backup.sh

3.下面的命令执行相同的任务
59 11 * * 1-5 /root/bin/backup.sh

4.每隔5分钟执行一次
*/5 * * * * /root/bin/check-status.sh

5.在每月第一天下午1:10执行
10 13 1 * * /root/bin/full-backup.sh

6.在工作日的下午11点执行
0 23 * * 1-5 /root/bin/incremental-backup.sh

Crontab命令选项
  • crontab –e :编辑crontab文件,如果不存在就创建一个
  • crontab –l :显示crontab文件内容
  • crontab -r :删除crontab文件
  • crontab -ir : 在用户删除crontab文件的之前提示用户

073 结合ssh-agent 使用 ssh-copy-id

结合ssh-add/ssh-agent 使用 ssh-copy-id
当我们没有给 -i参数传递值,或者~/.ssh/identity.pub 不存在,我们会得到下面的异常消息
jsmith@local-host$ ssh-copy-id -i remote-host

/usr/bin/ssh-copy-id: ERROR: No identities found

如果你通过ssh-add给ssh-agent加载密钥文件,那么ssh-copy-id会从ssh-agent得到密钥文件并复制到远程主机上。比如它会复制通过ssh-add -L命令得到的密钥文件。



jsmith@local-host$ ssh-agent $SHELL

jsmith@local-host$ ssh-add -L
The agent has no identities.

jsmith@local-host$ ssh-add
Identity added: /home/jsmith/.ssh/id_rsa
(/home/jsmith/.ssh/id_rsa)

jsmith@local-host$ ssh-add -L
ssh-rsa
AAAAB3NzaC1yc2EAAAABIwAAAQEAsJIEILxftj8aSxMa3d8t6JvM79D
aHrtPhTYpq7kIEMUNzApnyxsHpH1tQ/Ow==
/home/jsmith/.ssh/id_rsa

jsmith@local-host$ ssh-copy-id -i remote-host
jsmith@remote-host’s password:
Now try logging into the machine, with “ssh remote-
host’”, and check in: .ssh/authorized_keys to make sure
we haven’t added extra keys that you weren’t expecting.
[注意:这里加载了通过 ssh-add -L得到的密钥]

有关ssh-copy-id 三个需要小心的地方
  1. 缺省的公钥: ssh-copy-id使用~/.ssh/identity.pub作为缺省的公钥文件(比如,当你每个-i参数传值时)。但是,可能我想使用id_dsa.pub, or id_rsa.pub, 或者identity.pub作为缺省的公钥文件。如果这些文件存在,默认使用的是identity.pub文件。
  2. 未指定代理:如果在运行ssh-agent 时ssh-add -L 返回“The agent has no identities”(比如,ssh-agent没有密钥),ssh-copy-id 仍然会把“The agent has no identities”复制到远程主机的认证密钥文件中。
  3. 认证密钥文件中存在重复的密钥:我希望ssh-copy-id 命令可以识别出远程主机上的认证密钥文件中重复的密钥。但是如果你重复执行ssh-copy-id ,他会在认证密钥文件中增加多个重复的密钥而不会检查他们是否重复。尽管这样不会影响我们的工作,但是这样确实让认证文件看起来很凌乱。

Sunday, March 15, 2009

072 在OpenSSH中创建一个无需密码的登录

你可以通过以下3个步骤,使用ssky-keygen 和ssh-copy-id命令,不用密码就可以登录到远程的Linux服务器。
ssh-keygen用于创建公钥和密钥,ssh-copy-id 命令可以把本地的公钥复制到远程主机的authorized_keys 文件中,ssh-copy-id 同时会给远程主机的主目录中的~/.ssh和~/.ssh/authorized_keys设置适当的权限。
第一步:在本地通过ssh-key-gen创建公钥和密钥
jsmith@local-host$ ssh-keygen

Generating public/private rsa key pair.
Enter file in which to save the key
(/home/jsmith/.ssh/id_rsa):[Enter key]
Enter passphrase (empty for no passphrase): [Press
enter key]
Enter same passphrase again: [Pess enter key]
Your identification has been saved in
/home/jsmith/.ssh/id_rsa.
Your public key has been saved in
/home/jsmith/.ssh/id_rsa.pub.
The key fingerprint is:
33:b3:fe:af:95:95:18:11:31:d5:de:96:2f:f2:35:f9
jsmith@local-host

第二步:使用ssh-copy-id将公钥复制到远程主机上
jsmith@local-host$ ssh-copy-id -i ~/.ssh/id_rsa.pub
remote-host

jsmith@remote-host’s password:
Now try logging into the machine, with “ssh 'remote-
host’”, and check in:
.ssh/authorized_keys to make sure we haven’t added
extra keys that you weren’t expecting.

注意:ssh-copy-id将密钥文件加入到了远程主机的.ssh/authorized_key中。
第三步:无需密码登录到远程主机
jsmith@local-host$ ssh remote-host

Last login: Sun Nov 16 17:22:33 2008 from 192.168.1.2

[注意:SSH没有向你询问密码]

jsmith@remote-host$ [现在你已经登录到远程主机]

071 创建一个用户组并在这个组里增加一个用户

创建一个developers用户组
校验一下这个组是否成功的创建。
# grep developer /etc/group 
developers:x:511:

给这个组里增加一个用户
你不能通过useradd在一个组里创建一个已经存在的用户,否则你会得到一个错误信息。
# useradd -G developers jsmith 
useradd: user jsmith exists

# usermod -g developers jsmith

校验组是否修改成功
# grep jsmith /etc/passwd 
jsmith:x:510:511:Oracle
Developer:/home/jsmith:/bin/bash

# id jsmith
uid=510(jsmith) gid=511(developers)
groups=511(developers)

# grep jsmith /etc/group
jsmith:x:510:
developers:x:511:jsmith

070 Linux下创建用户

创建一个用户-基本命令
只听过用户名称:
# useradd jsmith

创建一个用户-提供更多的参数
你可以给useradd命令提供以下参数:
-c :增加对用户的描述
-e :指定用户的过期时间(格式为mm/dd/yy)

# adduser -c "John Smith - Oracle Developer" -e
12/31/09 jsmith

验证一下是否成功的增加了用户:
# grep jsmith /etc/passwd
jsmith:x:510:510:John Smith - Oracle
Developer:/home/jsmith:/bin/bash

修改用户密码
# passwd jsmith

Changing password for user jsmith.
New UNIX password:
BAD PASSWORD: it is based on a dictionary word
Retype new UNIX password:
passwd: all authentication tokens updated successfully.
注意:最好按照最佳建议设置一个安全的密码。

如何识别用户的缺省值
# useradd –D 

GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel

Thursday, March 12, 2009

069 创建交换swap 文件系统

创建一个交换(swap)文件的方法如下:
# dd if=/dev/zero of=/home/swap-fs bs=1M count=512 
512+0 records in
512+0 records out

# ls -l /home/swap-fs
-rw-r--r-- 1 root root 536870912 Jan 2 23:13
/home/swap-fs

使用mkswap命令在我们刚才创建的/home/swap-fs文件中创建一个Linux交换区域。
# mkswap /home/swap-fs  

Setting up swapspace version 1, size = 536866 kB

创建了这个交换区域后就可以通过swapon来激活它。
# swapon /home/swap-fs

把下面的代码加入到 /etc/fstab 中然后重启系统让其生效:
/home/swap-fs swap swap defaults 0 0

068 使用tune2fs 微调分区

使用tune2fs –l /dev/sda1命令可以显示文件系统信息:
# tune2fs -l /dev/sda1 

tune2fs 1.35 (28-Feb-2004)
Filesystem volume name: /home/database
Last mounted on: <not available>
Filesystem UUID: f1234556-e123-1234-abcd-
bbbbaaaaae11
Filesystem magic number: 0xEF44
Filesystem revision #: 1 (dynamic)
Filesystem features: resize_inode filetype
sparse_super
Default mount options: (none)
Filesystem state: not clean
Errors behavior: Continue
Filesystem OS type: Linux
Inode count: 1094912
Block count: 140138994
Reserved block count: 0
Free blocks: 16848481
Free inodes: 1014969
First block: 0
Block size: 2048
Fragment size: 2048
Reserved GDT blocks: 512
Blocks per group: 16384
Fragments per group: 16384
Inodes per group: 128
Inode blocks per group: 8
Filesystem created: Tue Jul 1 00:06:03 2008
Last mount time: Thu Aug 21 05:58:25 2008
Last write time: Fri Jan 2 15:40:36 2009
Mount count: 2
Maximum mount count: 20
Last checked: Tue Jul 1 00:06:03 2008
Check interval: 15552000 (6 months)
Next check after: Sat Dec 27 23:06:03 2008
Reserved blocks uid: 0 (user root)
Reserved blocks gid: 0 (group root)
First inode: 11
Inode size: 128
Default directory hash: tea
Directory Hash Seed: 12345829-1236-4123-9aaa-
ccccc123292b

你也可以使用tune2fs命令调整ex2/ext3 分区。比如如果你想调整文件系统的卷标,可以使用下面的命令:
# tune2fs -l /dev/sda1 | grep volume 
Filesystem volume name: /home/database

# tune2fs -L database-home /dev/emcpowera1
tune2fs 1.35 (28-Feb-2004)
# tune2fs -l /dev/sda1 | grep volume
Filesystem volume name: database-home

067 挂载分区

创建完分区后你可以把它挂载到一个挂载点上。
首先创建一个目录用于挂载这个分区:
# mkdir /home/database

然后用下面的命令挂载这个分区:
# mount /dev/sda1 /home/database

如果想重启系统后自动挂载分区,把下面的命令加入到/etc/fstab中:
/dev/sdaa /home/database ext3 defaults 0 2

066 使用mke2fsk格式化分区

分区之后还不能直接使用,我们必须对磁盘进行格式化。如果你现在就尝试查看磁盘内容的话,你会得到一个错误信息,它告诉你这不是一个有效的主磁盘。
# tune2fs -l /dev/sda1 

tune2fs 1.35 (28-Feb-2004)
tune2fs: Bad magic number in super-block while trying
to open /dev/sda1

Couldn't find valid filesystem superblock.

你可以使用下面的mke2fsk来格式化磁盘
# mke2fs /dev/sda1

mke2fs有如下参数:
-m 0 :这个参数可以指定预留给管理员用户的存储空间百分比,缺省是5%,在下面的例子中我们把它改成0。
-b 4096:指定字节块的大小。有效值是024, 2048 和 4096
# mke2fs -m 0 -b 4096 /dev/sda1 

mke2fs 1.35 (28-Feb-2004)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
205344 inodes, 70069497 blocks
0 blocks (0.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=71303168
2139 block groups
32768 blocks per group, 32768 fragments per group
96 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736,
1605632, 2654208, 4096000, 7962624, 11239424, 20480000,
23887872

Writing inode tables: done
Writing superblocks and filesystem accounting
information: done

This filesystem will be automatically checked every 32
mounts or 180 days, whichever comes first. Use tune2fs
-c or -i to override.

上面的命令创建了ext2格式的文件系统。要创建ext3格式,使用下面的命令;
# mkfs.ext3 /dev/sda1 

# mke2fs –j /dev/sda1

065 使用 fdisk 分区

当你在服务器上安装新的硬盘后,你必须使用fdisk工具对其进行适当的分区。
以下是5种你在执行fdisk时用到的选项:
  • n :创建新的分区
  • d : 删除现有的分区
  • p :打印分区表
  • w:在分区表中写入修改内容。
  • q:退出分区任务。
创建分区
在下面的里中我创建了一个/dev/sda1主分区。

# fdisk /dev/sda
Device contains neither a valid DOS partition table,
nor Sun, SGI or OSF disklabel Building a new DOS
disklabel. Changes will remain in memory only,
until you decide to write them. After that, of course,
the previous content won't be recoverable.

The number of cylinders for this disk is set to 34893.
There is nothing wrong with that, but this is larger
than 1024, and could in certain setups cause problems
with:
1) software that runs at boot time (e.g., old versions
of LILO)
2) booting and partitioning software from other OSs
(e.g., DOS FDISK, OS/2 FDISK)
Warning: invalid flag 0x0000 of partition table 4 will
be corrected by w(rite)

Command (m for help): p

Disk /dev/sda: 287.0 GB, 287005343744 bytes
255 heads, 63 sectors/track, 34893 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System

Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-34893, default 1):
Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-34893,
default 34893):
Using default value 34893

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

校验分区是否创建成功
# fdisk /dev/sda 

The number of cylinders for this disk is set to 34893.
There is nothing wrong with that, but this is larger
than 1024, and could in certain setups cause problems
with:
1) software that runs at boot time (e.g., old versions
of LILO)
2) booting and partitioning software from other OSs
(e.g., DOS FDISK, OS/2 FDISK)

Command (m for help): p

Disk /dev/sda: 287.0 GB, 287005343744 bytes
255 heads, 63 sectors/track, 34893 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System
/dev/sda1 1 34893 280277991 83 Linux

Command (m for help): q

02 Google App 快速入门之 Hello World!

Google App Engine 利用 CGI 与web服务器进行通信。当服务器从你的应用程序接收到请求时,它会在当前环境中根据请求数据执行应用程序,之后服务器会向客户端的标准输入输出流中写回响应数据,包括http headers和具体的内容。

让我们从开发一个显示简短信息的迷你应用程序开始吧。

创建一个简单的请求处理程序(Request Handler)

创建一个名为 helloworld 的目录。这个应用程序的所有文件都会放在这个目录下。

helloworld 目录下创建一个名为 helloworld.py 的文件,并输入下面的内容:

print 'Content-Type: text/plain' 
print '' 
print 'Hello, world!' 

上面这段Python代码向应用程序的请求返回一段包含了HTTP header信息、一个空行已经一个文本消息的 'Hello, world!'。

创建配置文件

一个App Engine包含一个名为 app.yaml 的配置文件,其中描述了哪个脚本文件被用于处理URLs。

我们需要在helloworld目录下创建这个文件并加入以下内容:

application: helloworld
version: 1 
runtime: python 
api_version: 1  
handlers: 
  - url: /.*   
    script: helloworld.py 

这段代码描述了以下信息;

  • 应用程序的名词为 helloworld ,在你最终部署这个应用程序的时候,你必须指定一个唯一的名称。在开发阶段这个值可以是任意内容。现在我们就将他简单的设置为 helloworld
  • 我们通过version变量来设置当前应用程序的版本号为1。当你更新了应用程序的版本后,App Engine可以记住以前的版本号,这样你就有机会回滚到以前的版本。
  • runtime变量告诉App Engine现在用的运行时环境是Python,当前的App Engine版本是1。以后App Engine会支持其他语言。
  • 对于最后一行表示每一个URL请求,如果其正则表达式可以匹配到/.*(这里表示任何连接)上时,就通过 helloworld.py 脚本处理。

测试应用程序

我们在上面一节中已经编写了一个可以处理任何连接的脚本,并在配置文件中进行了设置。现在你可以通过App Engine SDK 中自带的web服务器来测试一下。

你可以通过下面的命令启动并测试刚才的代码,我们需要将helloworld的路径作为参数传递给这个命令。

google_appengine/dev_appserver.py helloworld/ 

现在web服务器应该已经运行起来了,监听端口是8080。现在输入下面的地址:

http://localhost:8080/

如果想获得有关开发环境中web服务器更多的信息,比如修改缺省的8080端口,可以查看 the Dev Web Server reference 或者在刚才的命令后加上--help参数查看。

迭代开发

你可以在编写调试代码时让web服务器一直开着。服务器会监听你的源代码目录,一旦有改变它就会根据需要重新加载代码。你现在就可以试一下:让 web服务器一直开着,然后打开helloworld.py文件把其中的Hello World!消息改成其它内容。这时刷新依稀http://localhost:8080/ 页面看看有什么变化。如果想关闭web服务器只要在web服务器运行的命令窗口按下Control+C(或者其它‘终止命令’的按键)。在学习这边指南的 过程中你可以让web服务器一直开着,如果想重启它按照上面将的步骤就可以了。

接下来

现在你已经完成了一个完整的App Engine,你完全可以把它部署到实际的网络环境中,让别人看懂你的‘Hello World!’消息。不过,在部署之前我们考虑使用web应用程序框架来方便的给它增加一些新的功能。下一节我们将介绍 使用web应用程序框架

Wednesday, March 11, 2009

064 通过设置HISTIGNORE来忽略历史记录中特定的命令

有时候你可能不希望在历史记录中保存诸如pwd,ls这样的简单命令(这样看起来很乱)。你可以通过设置HISTIGNORE来忽略某些特定的命令。
注意将ls放在其中只能忽略ls命令但是不能忽略ls -l 命令,所以你必须明确指出你要在历史记录中忽略的命令是什么。

# export HISTIGNORE=”pwd:ls:ls –ltr:”

# pwd

# ls

# ls -ltr

# service httpd stop

# history | tail -3
79 export HISTIGNORE=”pwd:ls:ls -ltr:”
80 service httpd stop
81 history

[注意:历史记录中不在显示pwd和ls命令]

063 通过HISTSIZE关闭历史记录功能

如果你不想让系统记录你输入的内容,你可以通过把HISTSIZE设置为0来实现:
# export HISTSIZE=0

# history

# [注意:执行history命令什么都不会显示]

062 替换历史记录中某个命令的指定参数

在下面的例子中!cp:2会查找历史记录中以cp开头的命令和它的第二个参数,然后把它加到 ls -l命令后面:
# cp ~/longname.txt /really/a/very/long/path/long-
filename.txt

# ls -l !cp:2
ls -l /really/a/very/long/path/long-filename.txt

下面的例子中!cp:$ 会查找历史记录中以cp开头的命令和它的最后参数,然后把它加到 ls -l命令后面:
# ls -l !cp:$ 
ls -l /really/a/very/long/path/long-filename.txt

061 替换历史记录中的命令

你可能希望查找某个历史记录中的命令,然后保持这个命令所有的参数不变,而只是把这个命令本身换成你要执行的那个。
在下面的例子中你可以在vi命令后加上 !!:$ 参数然后vi后面就会自动跟上前一个命令的所有参数。

# ls anaconda-ks.cfg 
anaconda-ks.cfg

# vi !!:$
vi anaconda-ks.cfg

下面这个例子中vi后面的!^选项可以加上前一个命令的第一个参数。
# cp anaconda-ks.cfg anaconda-ks.cfg.bak 
anaconda-ks.cfg

# vi !^
vi anaconda-ks.cfg

01 GoogleApp 快速入门之 安装篇

介绍

欢迎使用Google App Engine!创建一个 Google App Engine非常简单,花几分钟就可以。开发并不复杂:上载你的应用程序,然后别人就可以马上看到你的应用,而且这些都是免费的并且没有任何限制。

在这篇指南中,你将创建一个简单的留言板程序,这样用户就可以把他们的留言发布到公共的留言板上。用户可以匿名留言或者登录他们的Google帐户后留言。

这个留言板程序将演示如何使用App Engine的数据库,如何将App Engine应用程序集成到Google帐户上,以及如何使用一个名为webapp的简单的Python web框架。这个应用还将演示如何使用Django模板引擎。

接下来

在开始开发Goole App Engine应用程序之前,我们需要先下载并安装它的软件开发环境。下一节 配置开发环境 .

配置开发环境

开发和部署Goole App Engine需要使用它的软件集成开发环境(SDK)。SDK包含一个用于模拟Goole App Engine环境的web服务器,一个本机版本的数据库,一个Google帐户,通过App Engine你可以获取URLs并从你的计算机上直接发送电子邮件。SDK可以运行在任何安装Python2.5的计算机上,你可以下载 Windows,Mac OS X和Linux版本的Python。

如果必要请从 Python 站点上下载并安装适合于你当前操作系统平台的Python2.5。Mac OS X 10.5 Leopard 用户的计算机上已经预装了Python2.5。

下载 App Engine SDK , 然后按照说明在你的计算机上安装SDK。

在这篇指南中你会用到SDK中的两个命令:

对于Windows用户来说:Windowsa安装程序将把上面的两个变量添加到环境变量的command path中。安装之后你就可以直接在命令窗口中使用这两个命令了。

对于Mac用户来说:Google App Engine Launcher中包含了这些命令。你可以在“GoogleAppEngineLauncher”菜单中通过“Make Symlinks...”把这些命令放到command path中。你可以通过Launcher来运行开发web服务器和部署你的应用,而不必通过命令行的方式。

如果你下载的是一个压缩包版本的SDK,你可以在 google_appengine 命令下找到这些命令。

接下来

在你把应用程序发布到网络上之前,你可以使用开发环境来开发和测试完整的App Engine 程序。接下来让我们写一些实际的代码。下一节 Hello,World

Tuesday, March 10, 2009

060 使用-c 选项清除所有之前的历史记录

有时候你希望把现在之前的所有历史记录都清除掉,那么可以执行下面的命令。


# history -c

059 使用HISTCONTROL变量强制系统不要在历史记录中保存指定的内容

在你执行命令时,你可以告诉系统不要记录你的命令。方法是把HISTCONTROL的值设置为ignorespace并且在你的命令前面加上一个空格。我看到很多新手系统管理员都喜欢使用这个方法因为这样他们就可以隐藏自己命令的执行记录。理解这个方法的工作方式非常简单。但是我们最好不要这样作。

# export HISTCONTROL=ignorespace

# ls –ltr

# pwd

# service httpd stop

[注意:这里的命令前面有一个空格,这样它的执行就不会被记录在历史记录中]

# history | tail -3
67 ls –ltr
68 pwd
69 history | tail -3

058 通过HISTCONTROL变量去除历史记录中的重复记录

上面将的例子中虽然可以去除重复的历史记录,但是条件是这些重复记录必须是连续出现的。要去除整个历史记录中所有的重复记录可以将HISTCONTROL 设置为erasedups:
# export HISTCONTROL=erasedups

# pwd

# service httpd stop

# history | tail -3
38 pwd
39 service httpd stop
40 history | tail -3

# ls -ltr

# service httpd stop

# history | tail -6
35 export HISTCONTROL=erasedups
36 pwd
37 history | tail -3
38 ls –ltr
39 service httpd stop
40 history | tail -6

[Note: The previous service httpd stop after pwd got
erased]

057 通过HISTCONTROL变量消除历史记录中重复的命令

在下面的例子中你执行了三次pwd命令,所以你会在历史记录中看到三个相同的pwd命令,我们可以通过把HISTCONTROL变量设置为ignoredups来去除重复的部分:
# pwd

# pwd

# pwd

# history | tail -4
44 pwd
45 pwd
46 pwd
47 history | tail -4

[注意:在执行了三次pwd命令后,你会在历史记录中找到同样重复的三个记录]

# export HISTCONTROL=ignoredups

# pwd

# pwd

# pwd

# history | tail -3
56 export HISTCONTROL=ignoredups
57 pwd
58 history | tail -4
[注意:尽管我们执行了三次pwd,但是历史记录中只显示一个pwd]

056 通过HISTFILE变量修改保存历史命令的文件名

缺省情况下历史记录保存在~/.bash_history 文件中。将下面的代码加入到 .bash_profile文件中再重新打开命令窗口,历史记录就会被保存在.commandline_warrior 中。一个比较使用的例子是,你可以通过这种方法跟踪不同命令窗口命令执行的历史记录。
# vi ~/.bash_profile 
HISTFILE=/root/.commandline_warrior

055 通过设置HISTSIZE变量来限制历史记录的行数

你可以把下面的代码加入到.bash_profile文件中,这样将限制历史记录的行数为450:
# vi ~/.bash_profile 

HISTSIZE=450
HISTFILESIZE=450

054 执行以指定字符开始的历史命令

输入!加上指定的字符将执行历史记录中以这个指定字符开始的命令。在下面的例子中输入!ps 将执行以ps开头的'ps aux | grep yp'命令。
# !ps 
ps aux | grep yp
root 16947 0.0 0.1 36516 1264 ?
Sl 13:10 0:00 ypbind
root 17503 0.0 0.0 4124 740 pts/0
S+ 19:19 0:00 grep yp

Monday, March 9, 2009

053 执行历史记录中某个特殊的命令

在下面的例子中,如果你想执行历史命令中的第四个命令,键入!4就可以了。
# history | more 
1 service network restart
2 exit
3 id
4 cat /etc/redhat-release

# !4
cat /etc/redhat-release
Fedora release 9 (Sulphur)

052 4种可以快速重复之前输入命令的方法

有时候,你可能希望重复执行之前的命令,下面列出4种方法。
  1. 使用向上键,找到之前执行的命令,然后运行它。
  2. 键入!! 找到刚才执行的命令,然后运行它。
  3. 键入!-1 找到刚才的前一个执行的命令,然后运行它。
  4. 执行 Control+P 显示签名的命令,然后运行他。

051 通过Control+R 查找历史记录

我非常相信这是你最常用的有关history的功能。你可能已经运行了一个非常长的命令,接下来当你要再次执行这个命令的时候你只需要搜索历史记录,找到它并重新执行就可以了。只要执行Control+R然后输入查找关键字就可以查找到历史命令了。
在下面的例子中我通过'red'关键字进行查找,查找结果是包含这个关键字的cat /etc/redhat-release命令:
# [注意: 键入Ctrl+R 将显示一个如下的 reverse-i-search 窗口] 

(reverse-i-search)'red': cat /etc/redhat-release
[Note: Press enter when you see your command, which
will execute the command from the history]

# cat /etc/redhat-release
Fedora release 9 (Sulphur)

有时候,你可能希望先编辑一下原来的命令然后再执行它。比如你查找httpd关键字,结果显示了service httpd stop命令,然后你可以把stop改成start然后再执行它。
# [注意: 键入Ctrl+R 将显示一个如下的 reverse-i-search 窗口]  
(reverse-i-search)`httpd': service httpd stop
[Note: Press either left arrow or right arrow key when
you see your command, which will display the command
for you to edit, before executing it]

# service httpd start

050 通过HISTTIMEFORMAT在命令行中显示时间戳

通常当你在命令行中键入history命令,会显示以往执行的命令。但是为了审计的需要,如果能够显示命令执行的时间戳就非常有用了:
# export HISTTIMEFORMAT=’%F %T ’

# history | more
1 2008-08-05 19:02:39 service network restart
2 2008-08-05 19:02:39 exit
3 2008-08-05 19:02:39 id
4 2008-08-05 19:02:39 cat /etc/redhat-release

注意,你也可以通过设置下面的别名来方便的使用history命令:
alias h1='history 10' 
alias h2='history 20'
alias h3='history 30'

Sunday, March 8, 2009

049 结合gzip, bzip2使用tar命令

如何与gzip一起使用tar
给tar命令加上z 参数就可以压缩tar.gz文件了
# tar cvfz /tmp/my_home_directory.tar.gz /home/jsmith

# tar xvfz /tmp/my_home_directory.tar.gz

# tar tvfz /tmp/my_home_directory.tar.gz

注意:在压缩的时候gzip的速度要快于bzip2
如何与bzip2一起使用tar
给tar命令加上j 参数就可以压缩tar.bz2文件了
# tar cvfj /tmp/my_home_directory.tar.bz2 /home/jsmith

# tar xvfj /tmp/my_home_directory.tar.bz2

# tar tvfj /tmp/my_home_directory.tar.bz2

注意:bzip2的压缩比要比gzip高。

048 Tar 命令入门

tar命令用于把一组文件压缩成一个归档文件:
Syntax: tar [options] [tar-archive-name] [other-file-
names]

如何把多个文件或者目录下的所有文件备份成一个归档文件
下面的命令在/tmp目录下创建了一个名为my_home_directory.tar 的归档文件,这个文件将包含/home/jsmith目录及其子目录下的所有文件和文件夹。
  • 参数c:代表创建一个归档文件。
  • 参数v:代表使用冗余模式,这样在执行命令的时候会显示附加信息。
  • 参数f:指出归档文件的名称。


# tar cvf /tmp/my_home_directory.tar /home/jsmith

如何显示tar归档中的所有文件
-t 选项用于显示归档文件中的所有文件:
# tar tvf /tmp/my_home_directory.tar

如何从归档文件中取出文件
x选项可以从归档文件中取出文件,它会把归档文件中的内容解压缩到但却目录下:
# tar xvf /tmp/my_home_directory.tar

如何把tar.gz文件中的内容解压缩到指定目录
# tar xvfz /tmp/my_home_directory.tar.gz –C 
/home/ramesh

047 校验zip归档文件

有时候你只是想校验一下规定文件的有效性而并不像真正的解压缩它,你可以在zip命令后加一个-t选项:
# unzip -t var-log.zip 

Archive: var-log.zip
testing: var/log/acpid OK
testing: var/log/anaconda.log OK
testing: var/log/anaconda.syslog OK

skip...

testing: var/log/wtmp OK
testing: var/log/wtmp.1 OK
testing: var/log/Xorg.0.log OK

No errors detected in compressed data of var-log.zip.

Thursday, March 5, 2009

046 给压缩文件加上密码保护

你可以通过给zip命令加上-P参数来给压缩文件加密:
# zip -P mysecurepwd var-log-protected.zip /var/log/*

如果上面的命令是你设置在一个后台执行的脚本中的话没什么不好,但是如果直接在命令行中运行,你可能不希望把密码直接显示在命令行历史中。所以我们通过如下所示的e参数来设置密码:
# zip -e var-log-protected.zip /var/log/*      
Enter password:
Verify password:
updating: var/log/acpid (deflated 81%)
updating: var/log/anaconda.log (deflated 79%)

下次当你解压缩这个文件的时候就需要通过密码才能继续:
# unzip  var-log-protected.zip 
Archive: var-log-protected.zip
[var-log-protected.zip] var/log/acpid password:

045 zip压缩命令的高级用法

zip命令提供了10个级别的压缩指令。
  • 0级:最低一层的压缩指令,它只是简单的把文件归档并没有进行压缩。
  • 1级:这一级别的压缩将进行最少的压缩,但是速度最快。
  • 6级:压缩级别更高
  • 9级:最高的压缩级别,压缩比率最高但速度最慢,按照我的看法,除非你要压缩的文件非常大,其他情况你都应该使用这个级别进行压缩。

下面的例子中我分别使用1,6,9三个基本进行压缩,你可以看到最终文件尺寸的不同:
# zip var-log-files-default.zip /var/log/* 
 
# zip -0 var-log-files-0.zip /var/log/*
 
# zip -9 var-log-files-9.zip /var/log/*
 
# ls -ltr
-rw-r--r-- 1 root root 2817248 Jan 1 13:05
var-log-files-default.zip
-rw-r--r-- 1 root root 41415301 Jan 1 13:05
var-log-files-0.zip
-rw-r--r-- 1 root root 2582610 Jan 1 13:06
var-log-files-9.zip

044 压缩命令

如何压缩多个文件?
syntax: zip {.zip 要压缩的文件名} {被压缩的文件名}

# zip var-log-files.zip /var/log/* 
  adding: var/log/acpid (deflated 81%)
  adding: var/log/anaconda.log (deflated 79%)
  adding: var/log/anaconda.syslog (deflated 73%)
  adding: var/log/anaconda.xlog (deflated 82%)
  adding: var/log/audit/ (stored 0%)
  adding: var/log/boot.log (stored 0%)
  adding: var/log/boot.log.1 (deflated 40%)
  adding: var/log/boot.log.2 (deflated 42%)
  adding: var/log/boot.log.3 (deflated 40%)
  adding: var/log/boot.log.4 (deflated 40%)

如何压缩一个目录及其下的文件?
# zip -r var-log-dir.zip /var/log/ 
updating: var/log/ (stored 0%)
  adding: var/log/wtmp (deflated 78%)
  adding: var/log/scrollkeeper.log (deflated 94%)
  adding: var/log/rpmpkgs.3 (deflated 68%)
  adding: var/log/spooler (stored 0%)
  adding: var/log/cron.2 (deflated 90%)
  adding: var/log/spooler.1 (stored 0%)
  adding: var/log/spooler.4 (stored 0%)
  adding: var/log/httpd/ (stored 0%)
  adding: var/log/rpmpkgs.1 (deflated 68%)
  adding: var/log/anaconda.log (deflated 79%)
  adding: var/log/secure.2 (deflated 93%)

如何解压缩*.zip文件
# unzip var-log.zip 
Archive: var-log.zip
  inflating: var/log/acpid
  inflating: var/log/anaconda.log
  inflating: var/log/anaconda.syslog
  inflating: var/log/anaconda.xlog
   creating: var/log/audit/

给unzip加上一个-v参数可以输出详细的解压缩过程
# unzip -v var-log.zip 

Archive: var-log.zip
Length Method Size Ratio Date Time CRC-32
Name
-------- ------ ------- ----- ---- ---- ------ ---
-
1916 Defl:N 369 81% 02-08-08 14:27 e2ffdc0c
var/log/acpid
13546 Defl:N 2900 79% 02-02-07 14:25 34cc03a1
var/log/anaconda.log

skip..

7680 Defl:N 411 95% 12-30-08 10:55 fe876ee9
var/log/wtmp.1
40981 Defl:N 7395 82% 02-08-08 14:28 6386a95e
var/log/Xorg.0.log
-------- ------- --- ---
----
41406991 2809229 93% 56
files

如何在解压缩的时候列出压缩包中的内容?
# unzip -l var-log.zip 

Archive: var-log.zip
Length Date Time Name
-------- ---- ---- ----
1916 02-08-08 14:27 var/log/acpid
13546 02-02-07 14:25 var/log/anaconda.log

..skip..

40981 02-08-08 14:28 var/log/Xorg.0.log
40981 02-08-07 14:56 var/log/Xorg.0.log.old
-------- -------
41406991 56 files

Wednesday, March 4, 2009

043 在PS1中使用shell脚本

你也可以在PS1变量中执行shell脚本。在下面的例子中~/bin/totalfilesize.sh将计算当前目录下所有文件的合计大小,这个脚本将会在PS1变量中执行。
ramesh@dev-db ~> cat ~/bin/totalfilesize.sh

for filesize in (ls -l . | grep "^-" | awk '{print
5}')
do
let totalsize=$totalsize+$filesize
done
echo -n "$totalsize"

ramesh@dev-db ~> export PATH=$PATH:~/bin

ramesh@dev-db ~> export PS1="\u@\h
[\$(totalfilesize.sh) bytes]> "

ramesh@dev-db [534 bytes]> cd /etc/mail

ramesh@dev-db [167997 bytes]>

[注意:这里在PS1变量中执行了totalfilesize.sh 脚本来显示当前目录下所有文件的大小]

042 在PS1变量中使用bash脚本

你也可以在PS1变量中使用bash脚本函数,像下面这样:
ramesh@dev-db ~> function httpdcount {
> ps aux | grep httpd | grep -v grep | wc -l
> }

ramesh@dev-db ~> export PS1="\u@\h [`httpdcount`]> "

ramesh@dev-db [12]>

[注意:这里显示了所有运行的httpd进程数]

你可以将下面的代码加入到~/.bash_profile 或者 ~/.bashrc文件中让改变永久生效:
$ vi .bash_profile 
function httpdcount {
ps aux | grep httpd | grep -v grep | wc -l
}
export PS1='\u@\h [`httpdcount`]> '

041 自定义你的命令窗口

通过下面的代码你可以创建符合自己要求的命令窗口。
  • \a :一个代表电脑鸣叫的ASII码
  • \d :显示星期和月份(“Tue May 26″)
  • \D{format} :其中的format会传给strftime(3),其结果将被加入到提示字符串中。空的格式代表显示本地时间,其{}括号是必须的。
  • \e:ASII转义字符
  • \h:主机名的第一部分
  • \H:主机名
  • \j:当前脚本管理的任务数
  • \l:当前脚本的根目录命令
  • \n:新的一行
  • \r:回车
  • \s:脚本的名称
  • \t :24小时制的当前时间 HH:MM:SS
  • \T:12小时制的当前时间 HH:MM:SS
  • \@ : 12小时制的当前时间 am/pm
  • \A:24小时制的当前时间 HH:MM
  • \u:当前用户名
  • \v:脚本窗口的版本
  • \V:脚本窗口的版本+分支版本
  • \w:当前路径名
  • \W:当前路径的根目录名
  • \! :运行的命令的历史序列号
  • \# :当前运行命令的序列号
  • \$:如果有效的UID是0那么显示 #其他的显示$
  • \nnn:显示八进制
  • \\:表示一个反斜杠
  • \[:显示一系列非打印字符集合的开始标志,这些字符可以用于控制命令窗口的行为
  • \]:显示一系列非打印字符集合的结束标志

Tuesday, March 3, 2009

040 使用tput来改变命令窗口的颜色

你还可以在PS1变量中通过tput来修改命令窗口的颜色。
 export PS1="\[$(tput bold)$(tput setb 4)$(tput setaf 
7)\]\u@\h:\w $ \[$(tput sgr0)\]“

tput设置颜色的选项为:
  • tput setab [1-7] -使用ANSI转义字符设置背景色。
  • tput setb [1-7] -设置背景色
  • tput setaf [1-7] --使用ANSI转义字符设置前景色。
  • tput setf [1-7] --设置前景色。
tput设置文本的选项为:
  • tput bold :黑体字模式
  • tput dim:半透明模式
  • tput smul :下划线模式
  • tput rmul:退出下划线模型
  • tput rev:打开反向模式
  • tput smso :进入标准输出模式
  • tput rmso:退出标准输出模式
  • tput sgr0:关闭所有属性
tput的颜色代码:
  • 0 – 黑色
  • 1 – 红色
  • 2 – 绿色
  • 3 – 黄色
  • 4 – 蓝色
  • 5 – 紫色
  • 6 – 青绿色
  • 7 - 白色

039 在命令窗口中显示多种颜色

你还可以在命令窗口中显示多种颜色,把下面的代码加入到~/.bash_profile文件中就可以实现:

function prompt {
local BLUE="\[\033[0;34m\]"
local DARK_BLUE="\[\033[1;34m\]”
local RED=”\[\033[0;31m\]”
local DARK_RED=”\[\033[1;31m\]”
local NO_COLOR=”\[\033[0m\]”
case $TERM in
xterm*|rxvt*)
TITLEBAR=’\[\033]0;\u@\h:\w\007\]’
      ;;
*)
TITLEBAR="
      ;;
esac
PS1=”\u@\h [\t]> ”
PS1=”${TITLEBAR}\
$BLUE\u@\h $RED[\t]>$NO_COLOR ”
PS2=’continue-> ‘
PS4=’$0.$LINENO+ ’
}

重新打开命令窗口你就可以看到刚才的改变了。

038 修改命令窗口的背景色

通过设置PS1变量中的\e[{code}m可以修改命令窗口的背景色。如下所示:
 export PS1="\e[47m\u@\h \w> \e[m "

[注意:这里设置的是浅灰色的背景]

结合设置命令窗口的前景色和背景色:
 export PS1="\e[0;34m\e[47m\u@\h \w> \e[m "

[注意:这里我们设置了浅灰色的背景色和浅蓝色的前景色]

将一下代码加入到~/.bash_profile 或者 ~/.bashrc文件中让改变永久生效:
 vi ~/.bash_profile
STARTFGCOLOR='\e[0;34m';
STARTBGCOLOR="\e[47m"
ENDCOLOR="\e[0m"
export PS1="$STARTFGCOLOR$STARTBGCOLOR\u@\h \w>
$ENDCOLOR"

你可以使用下面列出的选项来给命令窗口着色:
  • \e[40m
  • \e[41m
  • \e[42m
  • \e[43m
  • \e[44m
  • \e[45m
  • \e[46m
  • \e[47m