SHELL编程讲义

【1】SHELL范式

规定一个范式,有利于统一程序风格,增加可读性。对于编写SHELL,拷贝修改即可。 范式: ASSIGN SHELL/指定壳

DESCRIPTION/程序说明

BODY/程序体

扩展:

1 ASSIGN SHELL/指定壳,如果不指定壳,默认使用Bourne SHELL,建议使用KSH #!SHELL路径

1.1 CSH

#!/bin/csh

1.2 BSH

#!/bin/sh

1.3 KSH

#!/bin/ksh

2 DESCRIPTION/程序说明 #PROCEDURE NAME/程序名称

#PROCEDURE FUNCTION/程序功能说明

#AUTHOR/作者

#DATE/开发时间

#INPUT/输入 #OUTPUT/输出

#CALL/调用函数说明

#HISTORY/变更历史

3 BODY/程序体

INCLUDE LIBRARY /包含库文件

VARIABLE DEFINE/变量定义 FUNCTION DEFINE/函数定义

MAIN/程序入口

3.1 INCLUDE LIBRARY /包含库文件

. LIBRARY FILE/库文件名称

3.2 FUNCTION DEFINE/函数定义

#FUNCRION: FUNCTION NAME

#DESC : FUNCTION DESC

#INPUT : INPUT DESC

#OUTPUT : OUTPUT DESC

FUNCTION()

{

}

3.3 MAIN/程序入口(建议为) 程序启动说明 程序执行步骤 程序结束 exit 0

范式样例:

#!/bin/ksh

################################################################################# # 程序名 : update.sh

# # # # # # # # # # #

# 功能简介: 本程序完成WINV200R002M1D039P2升级 # 开发时间: 2002-05-05 # # # #

# 函数说明: 函数定义

# 作者 : zhongwei/20150 #

CheckBackupDir() 检查备分目录,不完毕则创建 检查是否已经升级 升级SMP的目录结构 备分SMP目录的文件

CheckDbinstallDir() 检查SMP的数据库安装脚本目录 UpdateSMPDir()

# CheckIfUpgraded() # BackupDb() # BackupFile() # UpdateDb() # UpdateFile() #

备分数据库的脚本、数据

升级数据库 升级文件

# #

# # # # #

# 修改历史: First Programming # 日期 : # 作者

# 修改说明:

################################################################################# #应用库函数,要求库函数文件与当前SHELL同一目录 . ./comm_func.sh.rc

#定义变量 #程序名称

ProgName="SMP Platform Upgrade" #标题

Title="WINV200R002 D039P2"

#目录和文件定义

WorkDir=`pwd` LogDir=$WorkDir/log

TempDir=$WorkDir/temp

#日志与标志文件 ErrFile=$LogDir/update.err LogFile=$LogDir/update.log

FlagFile=$LogDir/flag.flg

########################函数定义#################################### #################################################################### # 函数:PrintUsage

# 目的:定义打印用法函数。

# 输入:

# 输出:屏幕 #################################################################### PrintUsage() { echo "***************************************************************" echo " NAME : ${ProgName} " echo " VERSION : ${Title} " echo " SYSTEM : WIN SMP " echo " DESC : SMP platform or service upgrade " echo " NOTICE : " echo " COPYRIGHT : 2002, HUAWEI Tech. Co. Ltd. " echo "***************************************************************" echo " 1. Execute backup operation" echo " 2. Execute upgrade operation" echo " 3. Execute rollback operation" echo " 0. Exit" echo "Please input operation choice [0-3]:" }

… ########### Main ##############

… exit 0

##################### END OF PROCEDURE ###############

【2】SHELL编程语法

Script是以行为单位,我们所写的Script会被分解成一行一行来执行。而每一行可以是命令、注解、

或是流程控制指令等。如果某一行尚未完成,在行末加上"\" ,这个时候下一行的内容就会接到这一行的後面,成为同一行。

当Script中出现"#"时,再它後面的同一行文字即为注解,Shell会对其翻译。 在Script中要执行一个命令的方法和在命令列中一样,你可以前台或后台执行,执行命令时也会需要设定一些环境变量。

Script的流程控制和一般高级语言的流程控制没有什麽两样,也和高级语言一样有副程式。这些使得Script的功能更加强大。

1 SHELL基本术语与关键字

.

..

break

cd

continue

echo

eval

exec

exit

export

pwd

read

readonly

return

set

shift

test

times

trap

ulimit

umask

unset

wait

当前shell程序相同目录 当前shell程序的上一级目录 退出for、while、until或case语句 改变到当前目录 执行循环的下一步 反馈信息到标准输出 读取参数,执行结果命令 执行命令,但不在当前shell 退出当前shell 导出变量,使当前shell可利用它 显示当前目录 从标准输入读取一行文本 使变量只读 退出函数并带有返回值 控制各种参数到标准输出的显示 命令行参数向左偏移一个 评估条件表达式 显示shell运行过程的用户和系统时间 当捕获信号时运行指定命令 显示或设置shell资源 显示或设置缺省文件创建模式 从shell内存中删除变量或函数 等待直到子进程运行完毕,报告终止

2变量

Shell的类型只有字串变量,所以要使用数值运算则必须靠外部命令达成目的。而其变量种类有下列几种:

2.1 普通变量

这是最常使用的变量,我们可以任何不包含空白字元的字串来当做变量名称。 设定变量值时则用下列方式:

var=string #不能是var = string,即等号两边不能有空格。与判断语句正好相反,判断语句表

的=或者其他符号两边必须有空格,否则为赋值运算

取用变量时则在变量名称前加上一"$" 号,或者${name}。

name=Tom

echo name

echo $name

结果如下:

name

Tom

2.2环境变量

和使普通变量相似,只不过此种变量会将其值传给其所执行的命令。要将一使 用者变量设定为系统变量,只要加上:

export var或者export var=var_value 或者setenv var var_valued

name=Tom

export name

以下是使用者一进入系统之後就已设定好的系统变量:

$HOME 使用者自己的目录

$PATH 执行命令时所搜寻的目录

$TZ 时区

$MAILCHECK 每隔多少秒检查是否有新的信件

$PS1 在命令列时的提示号

$PS2 当命令尚未打完时,Shell要求再输入时的提示号

$MANPATH man 指令的搜寻路径

2.3 只读的使用者变量

和使用者变量相似,只不过这些变量不能被改变。要将变量设成只读的 ,只要加上:

readonly var

而若只打readonly则会列出所有只读的变量(ksh支持readonly命令。csh不支持,但是在shell程序中可以使用readonly修饰某个变量)。还有一点,系统变量不可以设定成只读的。 name=Tom

readonly name

echo $name

name=John

echo $name

(假设文件保存为aa)

结果如下:

aaa

aa[4]: name: This variable is read only

2.4 特殊变量

有些变量是一开始执行Script时就会设定,并且不以加以修改,但我们不叫它只读的系统变量,而叫它特殊变量,因为这些变量是一执行程式时就有了,况且使用者无法将一般的系统变量设定成只读

的。以下是一些等殊变量:

$0 这个程式的执行名字

$n 这个程式的第n个参数值,n=1..9

$* 这个程式的所有参数

$# 这个程式的参数个数

$$ 这个程式的PID

$! 执行上一个背景指令的PID

$? 执行上一个指令的返回值

$n,n只能为0-9的原因,是Bourne Shell的位置参数变量为$1~$9, 因此通过位置变量$n只能访问前9个参数。当你执行这个程式时的参数数目超过9 时,我们可以使用shift 命令将参数往前移一格,如此即可使用第10个以後的参数。除此之外,可以用set 命令改变$n及$*,方法如下: set string

如此$*的值即为string,而分解後则会放入$n。如果set命令後面没有参数, 则会列出所有已经设定的变量以及其值。 echo Filename: $0

echo Arguments: $*

echo No. of args.: $#

echo 2nd arg.: $2

shift

echo No. of args.: $#

echo 2nd arg.: $2

set hello, everyone

echo Arguments: $*

echo 2nd arg.: $2

结果如下:

Filename: ex1

Arguments: this is a test

No. of args.: 4 2nd arg.: is

No. of args.: 3

2nd arg.: a

Arguments: hello, everyone

2nd arg.: everyone

2.5 数组变量 (ksh支持)

name[index]=value

其中name为数组名称,index为数组下标,在ksh中数组最大支持1024,即index为0~1023. 或者

set –A name value1 value2…valuen

引用数组变量

${name[index]}

应用所有项: ${name[*]} #或者

${name[@]}

如: set –A ser pps ppip mvpn

echo ${ser[2]} echo ${ser[*]}

打印为:

mvpn

pps ppip mvpn

如: set –A ser pps ppip mvpn

echo $ser[2] echo $ser[*]

打印为:

pps[2]

pps[*]

2.6 SHELL变量

SHELL程序中可以直接使用一些变量。常用有: SECONDS #ftp程序中判断超时经常使用这个变量

IFS #域分割符,缺省为空格或者TAB键,可以由用户指定

3引用

某些字符在SHELL中具备特殊的含义:

如:& * + ^ $ ` " | ? [ ] ; ^ < >

可以使用双引号或者单引号或者\去掉特殊字符的含义,使成为一个普通字符.

3.1 ””可以去掉除$, \, ``之外的所有特殊字符的含义。

比如: >echo * #输出当前某个的所有目录与文件

>echo “*” #输出*字符

>echo “`date`” #输出为date命令打印的时间“Tue Sep 17 11:31:58 MDT 2002” >echo “$PATH” #输出当前用户的搜索路径

>echo “a\na” #输出为2行,一行一个a,此时\为特殊字符

3.2 ??单引号可以去掉除\以外,引号以内包含的任何特殊字符的含义,使成为一个普通字符. 比如:

>echo ?*? #输出*字符

>echo ?`date`? #输出`date`

>echo ?$PATH? #输出$PATH

>echo ?a\na? #输出为2行,一行一个a,此时\为特殊字符

3.3 \可以去掉& * + ^ $ ` " | ?的特殊含义,\本身的特殊含义可以用\去掉,比如\\后面一个\就

是普通字符

如:

>echo \* #输出*

4标准输入与输出

当我们在shell中执行命令的时候,每个进程都和三个打开的文件相联系,并使用文件描述符来引用这些文件。由于文件描述符不容易记忆, shell同时也给出了相应的文件名。下面就是这些文件描述符及它们通常所对应的文件名:

文件文件描述符

输入文件—标准输入0

输出文件—标准输出1

错误输出文件—标准错误2

系统中实际上有12个文件描述符,但是正如我们在上表中所看到的, 0、1、2是标准输入、输出和错误

command > filename 把把标准输出重定向到一个新文件中

command >> filename 把把标准输出重定向到一个文件中(追加)

command 1 > fielname 把把标准输出重定向到一个文件中

command > filename 2>&1 把把标准输出和标准错误一起重定向到一个文件中

command 2 > filename 把把标准错误重定向到一个文件中

command 2 >> filename 把把标准输出重定向到一个文件中(追加)

command >> filename 2>&1 把把标准输出和标准错误一起重定向到一个文件中(追加)

command < filename >filename2 把command命令以filename文件作为标准输入,以filename2文件作为标准输出

command < filename 把command命令以filename文件作为标准输入

command << delimiter 把从标准输入中读入,直至遇到delimiter(分界符)

command <&m 把文件描述符m作为标准输入

command >&m 把标准输出重定向到文件描述符m中

command <&- 关闭标准输入

比如常用dbaccess执行一个SQL串:

>dbaccess $TELLIN_DBNAME <<EOF >$errorfile 2>&1

delete from basetab_pps where msisdn=?130xxxxxxxx?

EOF

5重新定向

输入定向:可以从文件或者标准输入设备得到输入

<

输出定向:

> #将命令的屏幕输出定向到文件

>> #将命令的屏幕输出定向到文件,采用Append方式

管道定向:

| #将一个命令的输出定向到另外一个命令的输出(某些命令不支持直接|定向) 如:将一条SQL输出到dbaccess执行 >echo “update basetab_pps set multiserviceflag=?00000000000” msisdn=?135xxxxxxxx”|dbaccess $TELLIN_DBNAME

>ps –ef |grep “manager” |grep –v “grep” | wc –l #多次管道定向

得到命令返回值,输出到变量:

var=`command`

如:

>echo Time=`date "+%y-%m-%d %H:%M:%S"` #输出Time=02-09-17 18:30:06 where

6基本流程语句

6.1 顺序

6.2 条件语句if-then-fi if condition

then

...

fi

我们经常使用的书写方式:使用;符号,在一行中包含多条命令与语句

if condition ;then ...

fi

6.3 条件语句if-then-else-fi

If condition

then

...

else

...

fi

if condition1

then

...

elif condition2

then

...

else

...

fi

6.4 while条件循环 while express

do

...

done

#从循环中退出使用 break和continue命令

6.5 for循环 for var in arg1 arg2 ... argn do

...

done

#从循环中退出使用 break和continue命令

6.6 until循环

until express do

...

done

#从循环中退出使用 break和continue命令

6.7 case选择语句 case var in

var1)

...

;;

var2|var3)

...

;;

*)

;;

esac

如升级程序选择菜单就是利用case建立的: while true

do

#执行

echo ""

if [ "-${OprChc}" = "-1" ]; then Backup #备份

elif [ "-${OprChc}" = "-2" ]; then Upgrade #升级

elif [ "-${OprChc}" = "-3" ]; then

Rollback #回滚

elif [ "-${OprChc}" = "-0" ]; then

Log "Goodbye!"

Log ""

break

else

echo "Invalid input , please input again!"

fi

echo "" PrintUsage

read OprChc

done

6.8 select选择语句(ksh支持)

select选择语句一般与case语句联合使用,用户生成用户交互菜单。语法为:

select var in value1 value2 value3 … valuen do

done

select执行时会根据value项生成一个列表,并且每一项之前给一个从1开始递增的数字。用户选择某个数字,相当于选择value对应项,赋值给var变量。如:

1) value1

2) value2

3) value3

n) valuen

#?

一般do done之间使用case语句。语法扩展为: select var in value1 value2 value3 … valuen

do

case $var in

value1)

;;

value2)

;;

value3)

;;

valuen)

;;

*)

esac

done

7 比较操作

比较操作一般用在条件判断中,以下语法使用条件判断为例:

7.1 字符串比较

1)字符串相等比较

if [ $str = “value” ]; then #注意等号两边比较有空格,否则为赋值运算 …

fi

2)字符串是否为空

if [ “-$str” = “-” ]; then #-没有任何含义,只是为了增加可读性 …

fi

if [ “X$str” = “X” ]; then #X没有任何含义,只是为了增加可读性 …

fi

3)字符串不相等比较

if [ $str != “value” ]; then #注意等号两边比较有空格,否则为赋值运算 …

fi

if [ ! $str = “value” ]; then #!为not的含义,即取反

fi

7.2 数字比较

1)大于、大于等于

if [ $str -gt 100 ]; then #-gt表示大于

fi

if [ $str -ge 100 ]; then #-ge表示大于等于

fi

2)小于、小于等于

if [ $str -lt 100 ]; then #-lt表示小于

fi

if [ $str -le 100 ]; then #-le表示小于等于 …

fi

2)等于、不等于

if [ $str –eq 100 ]; then #-eq表示等于

fi

if [ $str -ne 100 ]; then #-ne表示不等于

fi

if [ ! $str -eq 100 ]; then #!表示取否,-eq表示等于 …

fi

7.3 判断条件连接

1)与/and,即要求表达式1与表达式2同时为真

if express1 && express 2 ; #&&表示与/and含义 then

fi

if [ str1 = “aa” ] && [ str2 = “bb” ] ;

then

fi

2)或/or,即要求表达式1或者表达式2之一为真

if express1 || express 2 ; #||表示或/or含义

then

fi

if [ str1 = “aa” ] || [ str2 = “bb” ] ;

then

fi

3)取反,

if ! express1 ; #!表示去反

then

fi

if [ ! $? –eq 0 ];

then

fi

8 SHELL函数

可以将SHELL中需要重复执行的代码写成函数,与C变成的函数一致。

8.1 函数格式

定义函数的格式为: 函数名()

{

...

}

或者

函数名(){

...

}

两者方式都可行。如果愿意,可在函数名前加上关键字function,建议增加。 function 函数名()

{

...

}

8.2 向函数传入参数

函数可以带参数调用,调用方式为

函数名称 参数列表

函数取得传入的参数,与SHELL得到调用的参数完全一致: 判断参数个数:

$#

取参数:

$1 $2 …

8.3 函数返回参数

函数可以使用return 返回调用参一个值。调用者可以在调用函数后得到函数的返回值: $?得到,如: #调用格式:aaa parameter

aaa() {

return 1

}

#错误用法

a=`aaa para` #无法得到返回值1

#正确用法

aaa para

ret=$?

如果使用exit,将退出SHELL程序

8.4 将常用函数写成库函数

为了重复利用代码,可以将函数写成库函数的方式,然后在SHELL中包含进行即可使用: . libraryfile

9其他基本语法

9.1 条件连接符 and与

命令行:command1 && command2 #如果command1执行成功,执行commnad2

如:rm * && echo "File successfully removed"

(建议不要使用以上语法,因为语法不常用,可读性不强) 表达式:express1 && express2

如:if [ $1 -eq 1 ] && [ $1 -eq 1 ]

then

... fi

or或

命令行:command1 || command2 #仅当前一个命令执行出错时才执行后一条命令 如:rm * || echo "File removed failed"

(建议不要使用以上语法,因为语法不常用,可读性不强) 表达式:express1 || express2

如:if [ $1 -eq 1 ] || [ $1 -eq 1 ]

then

...

fi

9.2 包含库函数

#. 空格之后将文件的路径, 一般放在程序的起始部分

. ./comm_func.sh.rc

9.3 信号处理

trap "echo ___ $0 interrupted ___; exit 1" 2

9.4 分割符

SHELL默认的分割符IFS为空格与TAB键。程序中可以使用定制的分割符

如:从dbaccess下载数据没有指定delimiter时,字段分割为”|”

OLD_IFS=$IFS

IFS=”|”

Read col1 col2 col3 < datafile

IFS=$OLD_IFS

9.5终端的一些知识

1) 使字符显示方式正常或者反转显示 echo “\033[m\c” #正常显示

echo “\033[7m\c” #反转显示

2)设置图形模式或者字符模式 echo “\033(B\c” #字符模式

echo “\033(0\c” #图形模式

3)从终端得到一个字符 TTY=`tty`

$1='`dd if=$TTY bs=1 count=1 2>/dev/null`'

4)定位光标位置

echo "\033[$1;$2H\c" #其中$1表示行,$2表示列

5) 设置终端参数

stty可以用来设置与限制终端属性,如:终端与计算机之间的传输率、退格、中断等。 echo[-echo] 是否回显

intr 生成中断信号,默认使用del按键生成

erase 退格键,即擦除前面一个字符

【3】常用概念命令与操作

1文件

1.1 文件类型,ls –al 中第一列的第一个字符:

drwxr-xr-x 12 smp20 sms 1024 Aug 13 15:36 .dt d 目录。

l 符号链接(指向另一个文件)。

s 套接字文件。

b 块设备文件。比如informix操作的存储文件为块设备 c 字符设备文件。比如/dev/null空设备

p 命名管道文件。即进程通信使用的PIPE文件

- 普通文件,或者更准确地说,不属于以上几种类型的文件

1.2 文件权限,ls –al 中第一列的第2-10个字符

(2-4字符) 文件属主的权限

(5-7字符) 同组用户的权限

(8-10字符) 其他用户的权限

1.3 改变权限位

chmod命令的一般格式为:

chmod [who] operator [permission] filename

who的含义是:

u 文件属主权限。

g 同组用户权限。

o 其他用户权限。

a 所有用户(文件属主、同组用户及其他用户)。

operator的含义:

+ 增加权限。

- 取消权限。

= 设定权限。

permission的含义:

r 读权限。

w 写权限。

x 执行权限。

s 文件属主和组set-ID。

t 粘性位*。

l 给文件加锁,使其他用户无法访问。

或者:

chmod 权限值 filename

文件属主 同组用户 其他用户

rwx rwx rwx

4+2+1 4+2+1 4+2+1

1.4 目录权限位

目录的读权限位意味着可以列出其中的内容。写权限位意味着可以在该目录中创建文件,如果不希望其他用户在你的目录中创建文件,可以取消相应的写权限位。执行权限位则意味着搜索和访问该目录

1.5 改变文件的属主

chown命令的一般形式为:

chown -R -h owner file

- R选项意味着对所有子目录下的文件也都进行同样的操作。- h选项意味着在改变符号链接文件的

属主时不影响该链接所指向的目标文件。一旦将文件的所有权交给另外一个用户,就无法再重新收回它的所有权

1.6 umask

umask命令确定了你创建文件的缺省模式。这一命令实际上和chmod命令正好相反

umask命令是在/etc/profile文件中设置的,每个用户在登录时都会引用这个文件,所以如果希望改变所有用户的umask,可以在该文件中加入相应的条目。如果希望永久性地设置自己的umask值,那么就把它放在自己$HOME目录下的. profile或.bash_profile文件中。

对于SMP或者SCP,我们定义在.cshrc中,这样登陆即生效。如:umask 002,这样创建的文件的权限为777-002=775

1.7 判断文件某些特性

-r file #是否存在并且可读

-w file #是否存在并且可写

-s file #是否存在并且文件大小大于0

-f file #是否存在并且是规则文件

-d file #是否存在并且为目录

-x file #是否存在并且可以执行

-p file #是否存在并且为管道文件

1.8 文件记录循环处理

使用while循环读取文件记录进行处理。其中文件输入采用 < 定向符。循环表达式为read命令,语法如下: while read var1 var2 …

do

#处理代码

done < filename

其中:

1一次读取一行数据。

2 可以将文件中一行数据以空格或者TAB键格开的域(字段)内容读入变量。如果变量数量小于域(字段)数量,则将前面部分一一对应,最后剩余域的所有内容读入最后一个变量。比如:

行:AAA BBB CCC

while read var1 var2

do

done

则var1=’AAA’, var2=’BBB CCC’

2 如果想使用其他字符间隔域(字段),可以修改IFS得到,比如:修改为| OLD_IFS=$IFS

IFS=|

while read var1 var2..

do

done

#恢复IFS原内容

IFS=$OLD_IFS

2数值操作

可以使用:expr或者bc命令,KSH可以使用let

使用 expr 应用程序

2.1 expr n1=3

n2=5

n=`expr $n1 + $n2 `

注意:+等操作符2侧需要使用空格格开

如: >expr 10000 + 1111 #相加

>expr 10000 \* 1111 #相乘

ksh 中可使用 let n1=3

n2=5

let n=n1+n2

2.2 bc

使用bc可以计算任意长度的计算,不会溢出

>echo "1000000000000000000000000000000*1111" | bc

111100000000000000000000000000000

2.3 进制转换

可使用printf命令转换

比如:16 to 10 十六进制数前加“0x"

test1=`printf "%d" 0x9d83000`

比如:10 to 16

test2=`printf "%x" 83000

3合并与分割

常用的合并与分割命令有:

? sort

? cut

? split

3.1 sort排序

sort -cmur -o 输出文件 –t 分割符 +n 输入文件

下面简要介绍一下s o r t的参数:

-c 测试文件是否已经分类。

-m 合并两个分类文件。

-u 删除所有复制行。

-r 逆向排序DESC,默认为正向ASC

如:将basetab_pps文件按第4个字段逆向排序 sort –t\| -r +3 basetab_pps.unl > basetab_pps.unl.sort

注意:不能使用-t|,因为|在SHELL中属于管道符号,需要使用\|

3.2 cut切割

cut用来从标准输入或文本文件中剪切列或域。剪切文本可以将之粘贴到一个文本文件。

下一节将介绍粘贴用法。 cut一般格式为:

cut [options] file1 file2

下面介绍其可用选项:

-c list 指定剪切字符数。

-f field 指定剪切域数。

-d 指定与空格和tab键不同的域分隔符。

-c用来指定剪切范围,如下所示:

-c1,5-7 剪切第1个字符,然后是第5到第7个字符。

-c1-50 剪切前50个字符。

-f 格式与-c相同。

-f1,5 剪切第1域,第5域。

-f1,10-12 剪切第1域,第1 0域到第1 2域。

如:从字符串中”aaabb:aaaaa:bbb”将”aaaaa”切割出来

>echo ”aaabb:aaaaa:bbb” | cut –d “:” –f2

3.3 split

split用来将大文件分割成小文件。有时文件越来越大,传送这些文件时,首先将其分割可能更容易。使用vi或其他工具诸如sort时,如果文件对于工作缓冲区太大,也会存在一些问题。因此有时没有选

择余地,必须将文件分割成小的碎片。

Split命令一般格式:

split –output-file-line input-filename output-filename

这里output-file-size指的是文本文件被分割的行数。Split查看文件时,output-file-line选项 指定将文件按每个最多1000行分割。如果有个文件有2800行,那么将分割成3个文件,分别有1000、1000、800行。每个文件格式为x[aa]到x[zz],x为文件名首字母, [aa]、[zz]为文件名剩余部分顺序字符组合,

4匹配或者过滤操作

4.1 grep的使用

grep可以从输入的字符中,过滤某些或者过滤掉某个特定字符的命令。

一般使用为: grep “特征字符串” inputFile

grep –v “特征字符串” inputFile

4.2 awk命令的使用

awk是可以使用很复杂,但是能完成某些特定功能,并且常使用的一个命令。使用用法: awk [–F 分隔符] ?模式? inputfile

-F可以指定域或者列之间的分割符,如果不指定,使用默认的分割符(空格或者TAB)。比如对于分割unload命令下载的文件, 可以指定 –F |

对于模式中的使用分割符分割后的域,标记$1,$2 . . . $n,$0标识所有的域。

为打印一个域或所有域,使用p r i n t命令

比如打印当前目录的所有文件的大小名称: >ls –al | awk ?{ print $5, $9}? #大小与文件名称使用空格格开,即$5,$9使用空格连接 >ls –al | awk ?{ print $5”|”$9}? #大小与文件名称使用|格开,即$5,$9使用|连接

使用BEGIN模式打印头部信息:

>ls –al | awk ?BEGIN {print “size filename”} { print $5”\t”$9}? #相当于打印列的标题 使用END模式打印尾部信息:

>ls –al | awk ?{print $5”\t”$9} END{print “finished”}? #在列出文件后,加上finished字符

awk中使用正则表达式

awk中正则表达式匹配操作用到的字符有:

\ ^ $ . [] | () * + ?

用法:

awk [-F 分割符] ?{if (express) 操作}?

即指定域满足express表达式的行,才打印出来.

如打印目录文件中包含sms的文件: >ls –al | awk ?{if ( $9~/sms/) print $0}?

如打印目录文件大小大于100000字节的文件:

>ls –al | awk ?{if ( $5>100000) print $0}?

awk中还有很多用法,在此不列出来

4.3 sed命令

5信号处理

信号就是系统向脚本或命令发出的消息,告知它们某个事件的发生。这些事件通常是内存错误,访问权限问题或某个用户试图停止你的进程。信号实际上是一些数字。下表列出了最常用的信号及它们的含义列出所有信号: >kill –l

HUP INT QUIT ILL TRAP IOT EMT FPE KILL BUS SEGV SYS PIPE ALRM TERM USR1

USR2 CLD PWR VTALRM PROF IO WINCH STOP TSTP CONT TTIN TTOU

一些信号的含义:

1 SIGHUP 挂起或父进程被杀死

2 SIGINT 来自键盘的中断信号,通常是< C T R L - C >

3 SIGQUIT 从键盘退出

9 SIGKILL 无条件终止

11 SIGSEGV 段(内存)冲突

15 SIGTERM 软件终止(缺省杀进程信号)

5.1 发出信号: kill –信号 进程号

注明:kill –9 进程号 杀死进程时,操作系统直接将进程从内核清除,不作退出的处理

5.2 检测信号或者捕捉信号

有些信号可以被应用程序或脚本捕获,并依据该信号采取相应的行动。另外一些信号不

能被捕获。例如,如果一个命令收到了信号9,就无法再捕捉其他信号。

当脚本捕捉到一个信号后,它可能会采

取下面三种操作之一:

1) 不采取任何行动,由系统来进行处理。

2) 捕获该信号,但忽略它。

3) 捕获该信号,并采取相应的行动

如果需要捕捉信号后,采用自定义的操作,可以使用trap命令:

trap name signal(s)

其中,name是捕捉到信号以后所采取的一系列操作。实际生活中, name一般是一个专门用来处理所捕捉信号的函数。Name需要用双引号(“ ”)引起来。Signal就是待捕捉的信号。

下表列出了一些最常见的trap命令用法:

trap "" 2 3 忽略信号2和信号3,用户不能终止该脚本

trap"commands" 2 3 如果捕捉到信号2或3,就执行相应的commands命令

trap 2 3 复位信号2和3,用户可以终止该脚本

如:收到3( SIGQUIT 从键盘退出),打印一行“proc received SIGQUIT and exit”

#!/bin/ksh

trap “fun_exit” 3

fun_exit()

{ echo “proc received SIGQUIT and exit” exit 1

}

echo “start running”

exit 0

6 eval命令

eval命名可以执行之后跟随的命令或者变量所赋的值或者表达式。比如:

用法1:

eval echo “aaa”

用法2:

command=env

eval $env

command=”echo aaa”

eval $command

用法3:

value=0

eval [ $? -gt $value ]&&j=1

eval [ $? -gt $value ]&& echo “successfully”

eval var=$#

eval命令在执行程序运行过程中赋值命令的变量非常有用。比如在SHELL编制的人机交互界面中,选中某个菜单项后执行没个命令或者函数,脚本本身不可能为每个菜单项case一遍。

【4】其他

4.1 使用不同的壳执行命令文件

1) 如果Script的第一个非空白字元不是"#",则它会使用Bourne Shell。

2) 如果Script的第一个非空白字元是"#"时,但不以"#!"开头时,则它会使用C Shell。

3) 如果Script以"#!"开头,则"#!"後面所写的就是所使用的Shell,而且要将整个路径名称指出来,这里建议使用第三种方式指定Shell ,以确保所执行的就是所要的。Bourne Shell的路径名称为/bin/sh ,而C Shell 则为/bin/csh。 我们一般使用ksh, 路径为/bin/ksh

4.2 使用不同SHELL的区别

BSH:

设置环境变量使用export var=var_value; var=var_valu; export var

CSH/KSH:

设置环境变量使用setenv var var_value

一些KSH独有的特征:

1)KSH环境变量

HISTSIZE:历史命令数量,默认为128,可以在.chsrc中将其设置为其他值

TMOUT :超时自动退出,用于一段时间没有键入命令,强制退出

1) 别名

可以定义自己的标识,标识定义的命令。比如:

alias dba dbaccess $TELLIN_DBNAME

2) 支持数组变量

4.3 SHELL程序的返回值不能超出255,否则返回值将不确定

4.4 read命令将输入的多余的part给最后一个变量 >read var1 var2

aa bb cc

>echo $var1

aa

>echo $var2

bb cc

4.5 调试

使用-x

1) 在SHELL程序指定执行为调试模式

#!/bin/sh –x

2) 在命令行中指定调试模式执行

指定SHELL –x 程序名称,如:

sh –x update_iuser214.sh

4.6 执行SHELL

前台执行:

>sh 程序名称

>程序名称

后台执行:

>sh 程序名称 &

>程序名称 &

4.7 移植性

目前智能业务部的设备选型中,小型机从IBM/HP/SUN 3家中选择。相应我们的SHELL一般需要在AIX,HP-UX,SunOS上应当保持一致。即SHELL程序一般需要在3中操作系统上进行移植。 可以使用uname –s确定机器的操作系统,比如:

#机器类型

OsType=`uname -s`

if [ "-$OsType" = "-SunOS" ]; then

elif [ "-$OsType" = "-HP-UX" ]; then

elif [ "-$OsType" = "-AIX" ]; then

else

echo "ERROR: system not support this machine type $OsType"

eixt 1

fi

大部分常见的UNIX命令在以上3中操作是一致的,但是某些命令则具有差异(

SHELL编程讲义

如ftp的ls在HP-UX为nlist)。如果碰到与操作系统相关的地方,则需要根据操作系统作相应处理。

附录:

一个SHELL编制的人机交互界面,里面使用的SHELL语法比较深入。如果能读懂或者编制同样程序,则表明你的SHELL教本功底已经足够深厚。如果不能读懂,可以挑战一下自己。

相关推荐