vim–additional features

vim-额外特性

重复命令

clip_image002

l  @@:重复上一个执行宏;

l  n以相同的方向重复上一个搜索命令;

l  N:以相反的方向重复上一个搜索命令;

l  . :重复上一个编辑命令;

l  @:重复上一个命令行

撤销和重做

clip_image003

l  u:可以撤销上次的操作;

l  Nu:可以撤销前N次的操作;

l  U:撤销当前行的所有修改;

l  :red或者CTRL+R:可以撤销还原;

打开光标下的文件

clip_image004

l  gf :在光标位于一个文件名上时,如果该文件就在当前目录,就可以打开该文件,但是会覆盖原来的文件;

l  CTRL+W f:可以打开一个新的窗口;

l  CTRL+W gf:可以打开一个新的窗口,此时会以tab的方式打开;

 

当然,就算没有绝对路径,vim也可以打开一些文件,比如c头文件和perl模块。

打开多个文件

使用vim file1 file2 file3….可以打开多个文件,但是同一时刻只能显示一个文件。

在一个session中,还可以使用:e anotherFile打开另一个文件。

在多个文件中,可以使用CTRL+^来切换,或者使用:next :previous来切换。

文件加密

Hacking for password

vim中使用:X然后输入密码就可是设置每次打开文件都要输入设置的密码,同时可以使用:set key=来取消密码。

保存会话

clip_image006

如果在编辑当前文件的时候,想编辑另外一个文件,可以使用:mksession来保存当前对话,等回来的时候,重新使用vim –S Session.vim即可打开原来保存的会话,这个会话会保存buffer、窗口大小、自定义选项、文件夹、当前目录等。

vim中执行shell命令

使用方式为:!cmd即可。

比如在修改源码的时候,我比较喜欢使用:!date这样就可以快速注释修改的时间了。

脚本控制

脚本控制

13.1 处理信号

13.1.1 Linux信号回顾

       可以使用kill –l查看Linux的信号集。

clip_image002

13.1.2 生成信号

       平时我们使用的CTRL+C就为发送了SIGINT信号;而CTRL+Z为生成了SIGTSTP信号,停止进程而不终止进程,停止进城后程序仍然爱留在内存中,能够从停止的地方继续运行。

13.1.3 捕获信号

       可以使用trap commands signals来捕获信号并拦截,如果脚本收到在trap命令中列出的信号,它将保护该信号不被shell处理。

       例如

       trap “echo haha” SIGINT SIGTERM,在该shell遇到两个信号时只是打印出haha而不会终止程序。

13.1.4 捕获脚本退出

       与上述相同,比如trap “echo haha” EXIT就会捕获退出信号,就算是CTRL+C也会捕获该信号。

13.1.5 移除捕获

       可以使用trap – signal来溢出捕获,但是如果在移除捕获之前收到了信号,脚本仍将根据trap命令处理该信号。

13.2 以后台模式运行脚本

13.2.1 以后台模式运行

       命令后添加&即可后台运行。

13.2.3 退出终端

       需要注意的是,运行后台进程的终端如果关闭的话,所有的后台进程也将退出。

13.3 在不使用控制台的情况下运行脚本

$nohup ./testshell &

nohup命令运行另一个命令阻塞发送到进程的任何SIGHUP信号,这可以防止在退出终端会话时退出进程。

13.4 作业控制

       重启、停止、终止和恢复作业的操作称为作业控制job control

13.4.1 查看作业

       命令jobs输出的信息中带有加号+的作业被视为默认作业,带有减号的作业是在处理完当前默认作业之后将称为默认作业的作业。在某一个时间点,无论shell中运行了多少作业,只能有一个带有加号+的作业,也只能有一个带有减号的作业。

13.4.2 重新启动停止的作业

       以后台模式启动bg n,以前台模式启动fg n,其中n为作业的编号。

13.5 变得更好

       默认情况下,从shell启动的所有进程在Linux系统上的调度优先级scheduling priority都相同,为0。调度优先级的范围为从-20(最高优先级)到20(最低优先级)。

13.5.1 nice命令

       nice命令可以在启动命令时设置它的调度优先级。不过只能让命令在更低的优先级下运行,而不能调高优先级。这是一个安全特性,防止用户以高优先级启动所有命令。

       格式为 : nice –n N command

13.5.2 renice命令

       格式为renice N –p PID ,其中N为想调至的优先级参数。

       命令renice可以指定运行进程的PID以更改优先级。与nice命令一样,renice命令也有几个限制:

 

l  只能对拥有的进程使用renice命令;

l  只能使用renice命令将进程调制更低的优先级;

l  跟用户可以使用renice命令敬爱那个任何进程调至任何优先级。

13.6 准确无误地运行

13.6.1 使用at命令调度作业

       at命令运行指定Linux系统运行脚本的时间。at命令将作业提交到一个队列,并指示shell在何时运行该作业。另一个命令atd以后台模式运行,并检查作业队列以运行作业。

       atd命令检查系统上的特殊目录,通常是/var/spool/at,以便运行使用at命令提交的作业。

       at命令的格式很简单:

       at [-f filename] time :其中filename为希望执行的脚本文件,time为希望运行的时间。其中time的方式可以发挥你的创造性了。

       使用at命令时,作业将提交到作业队列job queue中,有26中不同的作业队列可用于不同的优先级水平。使用小写字母az引用作业队列。

       默认情况下,所有的at作业都提交到作业队列a,即最高的优先级队列。如果希望以较低的优先级运行作业,可以使用-q参数指定字母。

       默认情况下,at作业完成后,不会再显示器显示任何内容,但是系统将生成一个电子邮件信息。

       使用atq命令可以查看系统中排队的作业。

       可以使用atrm N命令移除排队的作业,其中N为作业编号。

13.6.2 使用batch命令

       命令batchat稍有不同,batch命令的作用不是安排脚本在预设的时间运行,而是安排脚本在系统使用率低时运行

       如果Linux系统正处于高负载水平,batch命令将延迟提交作业的运行,直到系统负载减低为止。这对于服务器是个良好的特性,因为服务器在白天和夜晚的负载水平可能大不相同。batch会检查Linux系统当前的平均负载水平,如果平均负载低于0.8,它将运行在作业队列中的作业。

       batch命令的格式与at类似:

       batch [-f filename] [time]

13.6.3 调度定期脚本

       Linux系统中的cron程序可以调度需要定期运行的饿作业,cron程序在后台运行,它从特殊表格(cron表格)中查找需要调度运行的作业。

       cron表格的格式如下:

min hour dayofmonth month dayofweek command

       可以使用crontab –l查看现有的cron表格。

       对于cron存在的问题是,如果系统处于关闭状态,作业将无法执行。而anacron程序使用时间戳确定调度的作业是够在正确的时间间隔运行,如果确实错过了该作业的调度运行时间,它将尽快自动运行改作业。这意味着,如果Linux系统关闭了好几天,当它再次开启时,任何计划在系统关闭器件运行的作业都将自动运行。

       anacron表格的格式稍微不同于cron表格的格式:

period delay identifier command

13.7 从头开始

13.7.1 在启动时启动脚本

       可以写入rc脚本中,随系统一起启动。

13.7.2 随新shell一起启动

       写入.bashrc或者.bash_profile中,随着打开shell时启动。

 

创建函数

创建函数

14.1 基本脚本函数

       函数是被赋予名称的脚本代码块,可以在代码的任意位置重用。

14.1.1 创建函数                    

       格式为:

function name

{

       commands

}

或者为:

name()

{

       commands

}

14.2 返回值

       bash shell将函数看作小型脚本,并以退出状态结束。

14.2.1 默认退出状态

       默认情况下,函数的退出状态时函数的最后一条命令返回的退出状态。这是一种比较危险的做法,因为大部分情况下,我们不会再脚本的最后编写函数。而其他语句如果正常执行的话,就不会有提示信息了。

14.2.2 使用return命令

       return命令可以使用单个整数值来定义函数的退出状态,不过要注意两个错误:

l  记住在函数完成后尽快提取返回值;

l  记住退出状态的取值范围为0~255

14.2.3 使用函数输出

       例如一个函数为test,那么可以使用result=`test`来获取任意类型的返回值。

14.3 在函数中使用变量

       默认情况下,脚本中定义的变量都是全局变量,在函数外部定义的变量,在函数内部仍能正常访问。

       在变量前面加上local就能确保变量为局部变量。

14.5 函数递归

       自给(self-containment)是局部函数变量的一个特性。自给函数除了脚本通过命令行传递的变量,不适用函数之外的任何资源。

       这种特性使函数能够以递归方式调用。

14.6 创建库

       在当前文件夹创建一个库,testlib,那么我们在脚本中只需要source ./testlib或者用点好. ./testlib即可导入该库。

14.7 在命令行中使用函数

14.7.1 在命令行创建函数

       如果是一行命令,注意每条命令的结尾必须包含分号,这样shell才知道命令在那里分开;如果是多行命令,则不需要在每条命令的结尾添加分号,只需要按下ENTER键即可。

       注意,如果命令行中创建的函数与内置命令或其他命令同名,那么自定义函数将覆盖原有命令。

 

使用电子邮件

使用电子邮件

       使用shell脚本生成任何类型的报告,然后通过邮件发送,岂不酷毙了!

26.1 Linux电子邮件基础知识

       弄清楚什么软件包执行什么任务是从shell脚本获取电子邮件到邮箱的关键。

26.1.1 Linux中的电子邮件

       Linux系统的电子邮件系统源于Unix环境,Unix操作系统的主要目标之一就是将软件模块化。与可以处理所有必要功能的大型程序相比,Unix开发者创建较小的程序,每个小程序处理系统总功能的一小块。

       linux中,电子邮件功能被分隔为独立的小块,每一块分配给独立的程序。

       linux环境中,电子邮件进程通常分为三块功能:

l  邮件传输功能MTA

l  邮件分发功能MDA

l  邮件用户管理MUA

26.1.2 邮件传输代理

       MTA软件时Linux电子邮件系统的核心软件,它负责系统上进入和发出的邮件消息。对于每个发出的消息,MTA必须决定收件地址。如果目标主机是本地系统,则MTA可以直接将其发送到本地邮箱或将消息交给本地MDA去发送。

       然而,如果目标主机是远程邮件服务器,则MTA必须建立与远程主机的MTA软件的连接才能传送消息。MTA软件包将邮件发送到远程主机的方法有两种:

l  直接发送;

l  代理发送;

如果Linux系统直接连接到Internet,则总可以将消息发送给远程主机上的收件人。MTA软件使用域名系统DNS解析相应的网络IP地址以分发邮件消息,然后使用简单邮件传输协议Simple Mail Transfer ProtocolSMTP建立TCP连接。

       Linux环境中有许多不同类型的开源MTA程序,每种程序都提供了区别于其他程序的不同功能。目前为止,最流行的两个程序是:

l  sendmail

l  Postfix

26.1.3 邮件分发代理

       MDA程序的责任是将消息分发给本地用户。它从MTA程序接收消息并且必须清楚地判断以何种方式分发消息以及分发消息的地址。

       Linux系统上通常使用的3种邮箱类型是:

l  /var/spool/mail/var/mail

l  $HOME/mail

l  Maildir样式的邮箱目录

 

大多数Linux发行版使用/var/spool/mail/var/mail目录包含各个邮箱文件,每个文件对应系统上的一个用户账户。

少数Linux发行版允许将邮箱文件移动到每个用户的$HOME目录中。这提供了更高的安全性,因为每个邮箱文件位于已经设置好安全访问权限的区域中。

Maildir样式的邮箱是受一些更高级的MTAMDAMUA应用程序支持的新型功能。不想每个消息时邮件文件的一部分,它的邮箱是一个目录,而每个消息时该目录的单独的文件。这可以帮助削减邮箱破坏程序,因为单个文件不会破坏整个邮箱。

26.1.4 邮件用户代理

       Linux电子邮箱模型为每个用户使用本地的邮箱文件或目录来保存用户的消息。MUA程序的任务是提供一个让用户与邮箱互动的方法,以读取他们的消息。

       MUA不接收消息,它们只显示已经在邮箱中的消息。

Mailx

       Mailx程序是Linux环境中最受欢迎的命令行MUA程序。之所以取名为Mailx,是因为它是原本为Unix开发的邮件程序的升级版。

Mutt

       随着Unix环境的不断改进,MUA程序变得更高级。Unix系统上的第一个图形尝试是ncurses图形库。使用ncurses的程序可以处理光标在终端屏幕上的位置并将字符放置在终端上的几乎任何位置。

       一个使用ncurses库的MUA程序就是Mutt程序。

       Mutt程序使用组合键执行标准函数,如读取消息和撰写新消息。对于shell脚本程序员来说,最有用的功能可能就是直接从命令行发送消息,而不必借助文本图形模式。

图形电子邮件客户端

l  KDEKMail

l  GNOMEEvolution

26.2 设置服务器

       在将自动的邮件消息发送到全域之前,需要确保Linux系统上具备MTA包以及其配置正确。

26.2.1 sendmail

       sendmail MA包是Internet邮件服务器使用的最为流行的开源MTA包之一。

       主执行程序为sendmail,它通常以后台模式运行,侦听SMTP从远程邮件服务器的连接,以及为本地用户转发消息。

26.2.2 Postfix

       Postfix软件包迅速成为UnixLinux系统上最受欢迎的电子邮件包之一。Postfix是由Wietse Venema开发,旨在为标准Unix类型的服务器提供一种MTA选择,Postfix软件能够将任何UnixLinux系统转变为功能完全的电子邮件服务器。

26.3 使用Mailx发送消息

       shell脚本发送电子邮件的主要工具是Mailx程序,不仅可以用它以交互方式读取和发送消息,还可以使用命令行参数指定发送消息的方式。

26.4 Mutt程序

       Mutt程序是Linux命令行又一流行的电子邮件客户软件包,在1995年由Michael Elkins开发。它具有Mailx程序所不具备的一种功能,这使得它在shell脚本中使用起来非常便利。

       Mutt程序可以将文件发送为电子邮件消息的附件。

       通过无数的命令行参数可以直接从命令行自定义电子邮件消息,这正是我们想要在shell脚本中做的。

       Mailx程序非常类似,有一个不能使用Mutt程序在命令行指定的东西,即消息主题文件。如果未将文本重定向到Mutt程序,则它将以文本图形模式启动,同时显示编辑器窗口以供输入消息主体。

使用Web

使用Web

通常我们很少把shell脚本编程和Internet联系在一起,命令行世界似乎与色彩斑斓的、图形化的网络世界无源。然而,在脚本中有许多易于使用的工具可以用来获取web上的数据内容和其他网络设备

25.1 Lynx程序

       Lynx历史十分悠久,由Kansas大学的学生于1992年创建。

安装Lynx

       Lynx程序使用Linux中的curses文本图形库。这个也是不错的图形函数库。

Lynx命令行

       Lynx命令在从远程Web站点检索信息方面非常全面。当在浏览器中查看Web页面时,只能看到传输到浏览器的部分信息。Web页面由三种类型的数据元素组成:

l  HTTP头部信息;

l  Cookies

l  HTML内容。

其中Cookies为保存访问web站点的信息以便将来使用。

 

       Lynx程序允许以三种格式查看Web页面的实际HTML内容:

l  使用curses图形库在终端会话中显示为文本图形;

l  显示为从Web页面转储的原数据的文本文件;

l  显示为从Web页面转储的原HTML源代码的文本文件。

 

对于shell脚本来说,查看原数据或HTML源代码就像一个金矿一旦从Web站点捕获了检索的信息,就可以轻松地提取出各个信息片段

       Lynx程序的功能非常全面,但是全面就容易变得复杂。特别是在命令行参数方面。Lynx程序是Linux领域中最复杂的程序之一。

Lynx捕获数据

       shell脚本中使用Lynx时,很有可能试图从Web页面获取一小段信息。完成此操作的技术成为屏幕抓取(screen scraping)。

       执行屏幕抓取最简单的办法是使用带-dump选项的lynx。此选项不会再终端屏幕上显示Web页面,而是将文本数据直接显示到STDOUT上。

       当拥有Web页面的所有文本数据时,我们就可以为所欲为地使用sedgawk程序来从数据中提取我们需要的东东了。

比如下面的这个获取天气信息的shell脚本(虽然大家都知道,天气预报向来不准~):

sedhumidity

/Humidity/{

n

p

}

sedsunrise

/Sunrise/{

n

p

}

sedsunset

/Sunset/{

n

p

}

sedtemp

/Feels Like/{

n

p

}

sedvisibility

/Visibility/{

n

p

}

weather.sh

#!/bin/bash

#extract the current weather for Beijing

 

URL="http://weather.yahoo.com/china/beijing/beijing-2151330"

LYNX=`which lynx`

TMPFILE=`mktemp tmpXXXXXX`

$LYNX -dump $URL > $TMPFILE

 

humidity=`cat $TMPFILE | sed -n -f sedhumidity`

temp=`cat $TMPFILE | sed -n -f sedtemp`

sunrise=`cat $TMPFILE | sed -n -f sedsunrise`

sunset=`cat $TMPFILE | sed -n -f sedsunset`

visibility=`cat $TMPFILE | sed -n -f sedvisibility`

 

rm -f $TMPFILE

 

echo The current temp outside is : $temp

echo The current humidity is : $humidity

echo The current sunrise is : $sunrise

echo The current sunset is : $sunset

echo The current visibility is : $visibility

 

测试结果为

clip_image002

不过感觉还是浏览器好看呀,clip_image003

clip_image005

25.2 cURL程序

       cURL是由于Lynx的流行而催生出来的。OMGLynx厉害。curl是利用URL语法在命令行方式下工作的文件传输工具。它支持很多协议:FTP, FTPS, HTTP, HTTPS, GOPHER, TELNET, DICT, FILE 以及 LDAP等。

curl同样支持HTTPS认证,HTTP POST方法, HTTP PUT方法, FTP上传, kerberos认证,HTTP上传, 代理服务器, cookies 用户名/密码认证, 下载文件断点续传,上载文件断点续传,http代理服务器管道( proxy tunneling), 甚至它还支持IPv6 socks5代理服务器,,通过http代理服务器上传文件到FTP服务器等等,功能十分强大。

Windows操作系统下的网络蚂蚁,网际快车(FlashGet)的功能它都可以做到。准确的说,curl支持文件的上传和下载,所以是一个综合传输工具,但是按照传统,用户习惯称curl为下载工具。

       虽然cURL之前没有被用作Web页面浏览器,但是它允许从命令行或shell脚本以无人值守模式、需要使用简单的命令直接轻松发送和检索数据。

       默认情况下,cURLWeb页面的完整HTML代码返回给STDOUT。与Lynx类似,我们也可以使用标准的shell编程技术从转储的Web页面提取各个数据元素。

       cURL还可以批量下载文件,比如,我想下载PGPLOT就可以使用:

#!/bin/bash

# download the PGPLOT using cURL

cURL –s –o /home/leo/Download/pgplot5.2.tar.gz ftp://ftp.astro.caltech.edu/pub/pgplot/pgplot5.2.tar.gz

然后我们就可以使用at或者cron令将下载设置在晚间不使用PC或网络的时候下载,这对于希望下载一些容量比较大的文件还是很有帮助的。

25.3 使用zsh连接网络

       Zsh是比较新的shell,比较好的特性是插件模块zsh不是将许多功能都结合到核心zsh shell中,而是使用特殊的模块,以便用户可以获取和选择需要加载的命令,而其中就有TCP模块。

       Zsh shell中的TCP模块提供了许多可以直接从命令行使用的、非常好的网络功能。可以从命令行直接创建完整的TCP网络与另一个网络设备的会话。

25.3.1 TCP模块

       要将TCP模块安装到zsh,很简单,只需要%zmodload zsh/net/tcp即可。

       Ztcp命令使用文件描述符与打开的TCP连接交互。默认情况下,zsh使用环境变量$RESULT引用文件描述符,而TCP模块会将其转发给远程主机。类似地,如果远程主机发送了任何数据,则需要做的只是从$RESULT变量指定的文件描述符中读取内容,网络编程不过如此。这句话好狂妄,哈哈^_^

       比如下面这个例子:

clip_image007

Server.sh代码

#!/bin/zsh

#zsh TCP server script

zmodload zsh/net/tcp

ztcp -l 51510

fd=$REPLY

 

echo Waiting for a client…

ztcp -a $fd

clientfd=$REPLY

echo client connected

 

echo Welcome to my server >& $clientfd

 

while [ 1 ]

do

       read line <& $clientfd

       if [[ $line = "exit" ]]

       then

              break

       else

              echo Received: $line

              echo $line >& $clientfd

       fi

done

 

echo Client disconnected session

ztcp -c $fd

ztcp -c $clientfd

Client.sh代码

#!/bin/zsh

#zsh TCP client script

zmodload zsh/net/tcp

 

ztcp localhost 51510

hostfd=$REPLY

 

read line <& $hostfd

echo $line

 

while [ 1 ]

do

       echo -n "Enter text:"

       read phrase

       echo $ending $phrase to remote host…

       echo $phrase >& $hostfd

       if [[ $phrase = "exit" ]]

       then

              break

       fi

       read line <& $hostfd

       echo Received: $line

done

 

ztcp -c $hostfd