SHELL编程学习笔记
本文描述unix shell的各种应用实例,根据查阅资料和自我总结,作为自己今后复习的模板。本文搜集整理常用的shell应用实例,以例子详述unixshell部分命令的使用,着重于正则表达式以及grep、sed、awk等命令,涵盖业务开发中需要使用到的unix shell编程命令,供查阅或者自测使用,面向已经熟悉UNIX基本操作的开发人员。
注:
文中大部分表达式在sco-unixunixware 7下使用sh测试通过,有些规则或表达式不能通过测试或结果不正确,在本文档中使用波浪下划线将其标出,使用时应注意验证其在不同shell下的表现。
注:sco-unixunixware 7是操作系统的一个分类。
SCO UNIX是SCO公司(Santa CruzOperation Inc)所研制的多用户、多任务的功能齐全的网络操作系统,具有稳定性强、可靠性高、安全性好等诸多优点,在各行各业中的应用十分广泛。
本文不是命令手册,所以除部分命令如grep、sed、awk外,本文不详述讲述命令的各个参数,查看命令参数请使用man命令,本文着重于以实际例子讲述命令特征。
命令格式
一.shell与Unix平台
Unix平台 |
shell |
FreeBSD3.4 |
/bin/sh |
SGI IPIX6.5 |
/sbin/sh |
HUPX-11 |
usr/bin/sh |
UnixWare 7 |
$SHELL或/bin/sh |
Solaris 8 (固有的) |
/usr/bin/sh |
Solaris 8 (标准的) |
/usr/bin/ksh |
IBM AIX 4.3 |
/usr/bin/sh |
IBM AIX 4.3 (可信的) |
/usr/bin/tsh |
Linux |
/bin/sh |
二.shell基本知识
脚本参数:
shell脚本参数可以任意多,但只有前9各可以被访问,使用shift命令可以改变这个限制。参数从第一个开始,在第九个结束。
$0 这个程序的执行名字
$n 这个程序的第n个参数值,n=1..9
$* 这个程序的所有参数
$# 这个程序的参数个数
$$ 这个程序的PID
$! 执行上一个背景指令的PID
$? 执行上一个指令的返回值
其他参数:
$HOME 注册时进入的目录
$PATH 命令的搜索目录
$PS1 系统第一个提示符,一般为$
$PS2 系统第二个提示符,一般为>
$LINENO 所在的代码行,一般用来输出错误行号
shift [n] 将命令行参数往左移一位,但$0不变
export 变量名表 将变量名表所列变量传递给子进程
read 变量名表 从标准输入读字符串,传给指定变量
echo 变量名表 将变量名表指定的变量显示到标准输出
set 显示设置变量
env 显示目前所有变量
set命令可以重新设定参数表.如set hello wold命令会设定$*为字符串hello world,$n和$#也同时受影响。
shift命令可以将所有参数左移一个单位,$*、$n、$#均受影响。
数组(在sh中不支持):
${#varlist[@]} 数组元素个数
${datalist[index]} 数组元素
${#datalist[index]} 数组元素长度
执行命令:
1) command :直接执行命令command
2) shcommand:启动一个shellprocess执行命令command
3) . command:在本process中执行命令command
4) exec command:本Script将会被所执行的命令所取代,当这个命令执行完毕之後,本Script也会随之结束。
二.chmod命令
格式: chmod [who]operator[permission] filename
[who]:
u 文件属主权限。
g 同组用户权限。
o 其他用户权限。
a 所有用户(文件属主、同组用户及其他用户)。
operator:
+ 增加权限。
- 取消权限。
= 设定权限
[permission]:
r 读权限
w 写权限
x 执行权限
s 文件属主和组set -ID
t 粘性位* (不考虑)
l 给文件加锁,使其他用户无法访问
chmod –R -h… //递归子目录, 遇到链接文件时不影响目标文件
目录的权限:
(1) r-可以列出目录内容; w-在目录中创建文件; x-目录可以搜索和访问
(2) 如果目录权限—x,目录中有一个可执行脚本,还是可以执行的
(3) 目录的权限会覆盖目录中文件的权限
三.grep命令
搜索文本的匹配内容。
格式: grep [-option] pattern [filename]
选项:
-c 只输出匹配行的计数
-i 不区分大小写(只适用于单字符)
-h 查询多文件时不显示文件名
-l 查询多文件时只输出包含匹配字符的文件名
-n 显示匹配行及行号
-s 不显示不存在或无匹配文本的错误信息
-v 显示不包括匹配文本的所有行
四.sed
查找和编辑文本。
格式:
(1)直接键入命令
sed [-option] command_line filename
(2)将sed命令插入脚本文件,然后调用sed
sed [-option] -f program_file filename
(3)将sed命令插入脚本文件,并使脚本可执行
sed program_file [-option] filename
选项:
n 不打印;sed不把编辑行写到标准输出,默认为打印所有行(编辑的和未编辑的)。p命令可以用来打印编辑行。
c 下一个命令是编辑命令。在使用多项编辑时要加入该选项。
f 如果正在调用sed脚本,要使用此选项。此选项同志sed脚本支持所有的sed命令。
五.awk命令
awk是一种程序语言,对于资料的处理具有很强的功能,对于文档里的资料做修改、比较、抽取等处理,awk能够以很短的程序轻易地完成。如果使用C 语言写程序完成上述的操作不方便且很花费时间,所写的程序也会很大。
awk能够依照用户定义的格式来分解输入的资料也可以依照用户定义的格式来打印资料。
awk可用于在对象文件中逐行读取记录,按照命令中定义的匹配模式寻找相关记录,然后对该记录进行操作动作。
格式:
(1)直接键入命令:
awk [-Fchar] ‘command_line’ filename
(2)将awk命令插入脚本文件,然后调用awk:
awk -f program_file filename
前一种形式的-Fchar确定间隔符,command_line为操作动作,filename为对象文件。
后一种形式的program_file是指用户按一定格式编制好的对对象文件的匹配与操作。
六.find命令
通过文件名或其它特征查找文件。
格式:
find [path-list] [predicate-list]
选项:
-type tp 文件类型为tp:
b 块特别文件
c 字符设备特别文件
d 目录文件
f 普通文件
p 管道文件(FIFO)
s socket
I 符号链接文件
-user uname 文件属于用户uname。
-group gname 文件属于组gname。
-size n 文件是n块大小(每块512字节),若n后跟一个c,单位为字节。
-atime n 在n天内已访问过此文件。
-mtime n 在n天内已修改过此文件
-ctime n 在n天内文件被修改、属性(拥有者、组、链接数等)被修改。
-exec command{} \; 执行命令
-print 打印当前路径名
-newer file 修改时间比file文件晚
七.test命令
命令格式
testexpression
expression中包含一个以上的判断准则以作为test评诂的标准。两准则间用"-a"代 表逻辑AND 运算,"-o"代表逻辑OR运算,而在准则前放置一"!"代表NOT 运算。如 果没有括号,则优先权则为"!"> "-a" > "-o" 。和expr命令相同,相使用左右括 号时,必须在其前面加上"\"。以下是有关准则的叙述(符合叙述时传回真,否则传回伪):
stringstring不为空白字串
-nstring string的长度大於0
-zstring string的长度等於0
string1=string2 string1等於string2
string1!=string2 string1不等於string2
int1 -gt int2 int1大於int2
int1 -ge int2 int1大於等於int2
int1 -eq int2 int1等於int2
int1 -ne int2 int1不等於int2
int1 -le int2 int1小於等於int2
int1 -lt int2 int1小於int2
-r filename 档案可读取
-w filename 档案可写入
-x filename 档案可执行
-f filename 档案为一般档
-d filename 档案为目录
-s filename 档案为非空的一般档
test -r "$filename" -a -s "$filename"
八.expr命令
命令格式
expr expression
expression是由字串以及运算子所组成,每个字串或是运算子之间必须用空白隔开 。下表是运算子的种类及功能,而优先顺序则以先後次序排列,可以利用小括号来改变运算的优先次序。其运算结果则输出至标准输出上。
:字串比较。比较的方式是以两字串的第一个字母开始,而以第二个字串的 字母结束。如果相同时,则输出第二个字串的字母个数,如果不同时则传 回0 。
*乘法
/除法
%取馀数
+加法
-减法
<小於
<=小於等於
=等於
!=不等於
>=大於等於
>大於
&AND运算
|OR运算
当expression中含有"*", "(",")" 等符号时,必须在其前面加上"\",以免被 Shell解释成其它意义。
expr2 \* \( 3 + 4 \) 其输出为14
九.流程控制语法
1. if then 语法
if(condition)
then
then-commands
fi
2. if then else 语法
if(condition)
then
then-commands
else
else-commands
fi
3. ifthen elif语法
if(condition1)
then
commands1
elif(condition2)
then
commands2
else
commands3
fi
4. for in 语法
for varin arg-list
do
commands
done
5. for 语法
for var
do
commands
done
例如
for arg
do
echo $var
done
调用 varlist.sh 111 222 3333
输出: 111
222
333
6. while 语法
while(condition)
do
commands
done
7. until 语法
until(condition)
do
commands
done
8. break及continue
这两者是用於for,while, until 等循环控制下。break 会跳至done后方执行 ,而continue会跳至done执行,继续执行循环。
9. case 语法
case strin
pat1)
commands1
;;
pat2)
commands2
;;
esac
而pat 除了可以指定一些确定的字串,也可以指定字串的集合,如下
* 任意字串
? 任意字元
[abc] a,b, 或c三字元其中之一
[a-n] 从a到n的任一字元
| 多重选择,如A|a
十.shell脚本调试
1.启动调试
启动调试Shell脚本的基本语法为:
$/bin/sh option script arg1 arg2 ... argN
这里显式声明了要执行脚本的Shell为/bin/sh,script是脚本的名字,arg1到argN是脚本的参数, option为调试选项,如下所示:
-n 读所有的命令,但不执行它们
-v 在读时显示所有的行
-x 在执行时显示所有命令和它们的参数。该选项常称为shell 跟踪选项或
改变脚本的第一行,象下面那样在该行声明一个调试选项:
#!/bin/sh option
2.使用set命令
在每个调用激活调试模式中,调试模式的缺省行为对脚本中从第一行到最后一行都有效。有时我们只需要调试特定的函数或脚本的一部分,这时调试整个脚本就有些多余。通过使用set命令,我们可以在shell脚本的任何地方启动或取消调试,其基本语法为:
set[-|+] option
这里的option选项与上面的相同。
3.语法检查
在处理任何Shell脚本时,应在准备执行它之前检查脚本的语法,这使我们能改正许多问题。要启动语法检查可使用-n选项,如对于上面的buggy.sh脚本,象下面那样检查语法:
$/bin/sh-n ./buggy.sh
实例讲解
一.模式匹配
1.ls显示所有以hosts.开头的文件
ls –l hosts.*
2.ls显示包含x,y,z字符的所有文件
ls –d *[x-z]*
二.正则表达式
1.grep匹配/etc/services文件中以ftp字符串开头的哪些文本行
grep ‘^ftp’ /etc/services
2.grep匹配以system文本结尾的行。
grep ‘system$’ file
3.grep匹配仅包含一个#字符的行。
grep ‘^#$’ file
4.grep匹配以<abc>或者[abc]开头的行
grep ‘[[<]abc[]>]’ file
5.grep匹配以Ftp或者ftp开头的行
grep ‘^[Ff]tp’ file
6.grep匹配F或者f以外的字符
grep ‘[^Ff]’ file
7.grep匹配除大写字符以外的字符
grep ‘[^A-Z]’ file
8.grep匹配以ftp或telnet开头的文本行
grep ‘^ftp|^telnet’ file
9.grep匹配以ftp开头,后跟0个或多个-agent的文本行
grep ‘^ftp(-agent)?’ /etc/services
或 grep ‘^ftp(-agent)*’ /etc/services
注:
a)在scounix下,上面的单括号前要加转义符\
b)在sunos 5.8下,不论加不加单括号均不支持。
10.grep匹配以ftp开头,后跟1个或多个-agent的文本行
grep ‘^ftp(-agent)+’ /etc/services
说明同上。
11.grep匹配带有数字6,后跟至少3个0的文本行(使用-E启用边界特性)
grep -E ‘60\{3,\}’ /etc/services
12.grep匹配含有(abc)的文本
grep ‘\(abc\)’ file
13.常用正则表达式举例
正则表达式 |
匹配功能 |
^[the] |
以the开头行 |
[Ss]igna[lL] |
匹配单词signal,signaL,Signal,SignaL |
[Ss]igna[lL]\. |
同上,但加一个句点 |
[mayMAY] |
|
^USER$ |
只包含USER的行 |
[tty]$ |
以tty结尾的行 |
\. |
带句点的行 |
^d..x..x..x |
对用户、用户组及其它用户组成员有可执行权限的目录 |
^[^l] |
排除关联目录的目录列表 |
[.*0] |
0之前或之后加任意字符 |
[000*] |
000或更多个 |
[iI] |
大写或小写I |
[iI][nN] |
大写或小写I或n |
[^$] |
空行 |
[^.*$] |
匹配行中任意字符 |
^……$ |
包括6各字符的行 |
[a-zA-Z] |
任意单字符 |
[a-z][a-z]* |
至少两个小写字母 |
[^0-9\$] |
非数字或美元表示 |
[^0-9A-Za-z] |
非数字或字母 |
[123] |
1到3中的一个数字 |
[Dd]evice |
单词Device或device |
De..ce |
前两个字母为De,后跟两个任意字符,最后为ce |
^.$ |
仅有一个字符的行 |
^\.[0-9][0-9] |
以一个句点和两个数字开始的行 |
“’Device’” |
单词Device |
De[Vv]ice\. |
单词Device.或DeVice. |
[0-9]\{2\}-[0-9]\{2\}-[0-9]\{4\} |
日期格式dd-mm-yyyy |
[1-9][0-9]\{1,2\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\} |
IP地址格式nnn.nnn.nnn.nnn |
[^.*$] |
匹配任意行 |
14.grep精确匹配:在抽取字符串后加\>。
grep “48\>” file
15.grep消除大小写:加入-i选项
grep -I “sept” file
16.特殊字符:$ . ‘ “ * [ ] ^ | \ + ?
如果要查询这些字符,需要在前面加转义字符\。
17.grep判断变量含有[HOST]字符串
if[ "1" -eq "`echo "$VarName" | grep -c'\[HOST\]'`" ]; then
18.grep判断变量含有[xxx]字符串
if[ "1" -eq "`echo "$VarName" | grep -c '\[.*\]'`"]; then
19.grep匹配后缀为c,h,j,s,cpp,hpp的文件
EXT_ALL='chjs'
EXT_PP='ch'
EXT_NO_PP='js'
ls $1 | grep"\.[$EXT_ALL][p]\{0,2\}$" | grep -v "\.[$ EXT_NO_PP][p]\{1,2\}$" | grep -v "\.[$EXT_PP][p]\{1\}$"
20.正则表达式语法
来自msdn,仅供参考。
Here aresome examples of regular expressions:
Expression |
Matches |
/^\s*$/ |
Match a blank line. |
/\d{2}-\d{5}/ |
Validate an ID number consisting of 2 digits, a hyphen, and an additional 5 digits. |
/<\s*(\S+)(\s[^>]*)?>[\s\S]*<\s*\/\1\s*>/ |
Match an HTML tag. |
The following table contains thecomplete list of metacharacters and their behavior in the context of regularexpressions:
Character |
Description |
\ |
Marks the next character as a special character, a literal, a backreference, or an octal escape. For example, 'n' matches the character "n". '\n' matches a newline character. The sequence '\\' matches "\" and "\(" matches "(". |
^ |
Matches the position at the beginning of the input string. If the RegExp object'sMultiline property is set, ^ also matches the position following '\n' or '\r'. |
$ |
Matches the position at the end of the input string. If the RegExp object'sMultiline property is set, $ also matches the position preceding '\n' or '\r'. |
* |
Matches the preceding character or subexpression zero or more times. For example, zo* matches "z" and "zoo". * is equivalent to {0,}. |
+ |
Matches the preceding character or subexpression one or more times. For example, 'zo+' matches "zo" and "zoo", but not "z". + is equivalent to {1,}. |
? |
Matches the preceding character or subexpression zero or one time. For example, "do(es)?" matches the "do" in "do" or "does". ? is equivalent to {0,1} |
{n} |
n is a nonnegative integer. Matches exactly n times. For example, 'o{2}' does not match the 'o' in "Bob," but matches the two o's in "food". |
{n,} |
n is a nonnegative integer. Matches at least n times. For example, 'o{2,}' does not match the "o" in "Bob" and matches all the o's in "foooood". 'o{1,}' is equivalent to 'o+'. 'o{0,}' is equivalent to 'o*'. |
{n,m} |
M and n are nonnegative integers, where n <= m. Matches at leastn and at most m times. For example, "o{1,3}" matches the first three o's in "fooooood". 'o{0,1}' is equivalent to 'o?'. Note that you cannot put a space between the comma and the numbers. |
? |
When this character immediately follows any of the other quantifiers (*, +, ?, {n}, {n,}, {n,m}), the matching pattern is non-greedy. A non-greedy pattern matches as little of the searched string as possible, whereas the default greedy pattern matches as much of the searched string as possible. For example, in the string "oooo", 'o+?' matches a single "o", while 'o+' matches all 'o's. |
. |
Matches any single character except "\n". To match any character including the '\n', use a pattern such as '[\s\S]'. |
(pattern) |
A subexpression that matches pattern and captures the match. The captured match can be retrieved from the resulting Matches collection using the$0…$9 properties. To match parentheses characters ( ), use '\(' or '\)'. |
(?:pattern) |
A subexpression that matches pattern but does not capture the match, that is, it is a non-capturing match that is not stored for possible later use. This is useful for combining parts of a pattern with the "or" character (|). For example, 'industr(?:y|ies) is a more economical expression than 'industry|industries'. |
(?=pattern) |
A subexpression that performs a positive lookahead search, which matches the string at any point where a string matchingpattern begins. This is a non-capturing match, that is, the match is not captured for possible later use. For example 'Windows (?=95|98|NT|2000)' matches "Windows" in "Windows 2000" but not "Windows" in "Windows 3.1". Lookaheads do not consume characters, that is, after a match occurs, the search for the next match begins immediately following the last match, not after the characters that comprised the lookahead. |
(?!pattern) |
A subexpression that performs a negative lookahead search, which matches the search string at any point where a string not matchingpattern begins. This is a non-capturing match, that is, the match is not captured for possible later use. For example 'Windows (?!95|98|NT|2000)' matches "Windows" in "Windows 3.1" but does not match "Windows" in "Windows 2000". Lookaheads do not consume characters, that is, after a match occurs, the search for the next match begins immediately following the last match, not after the characters that comprised the lookahead. |
x|y |
Matches either x or y. For example, 'z|food' matches "z" or "food". '(z|f)ood' matches "zood" or "food". |
[xyz] |
A character set. Matches any one of the enclosed characters. For example, '[abc]' matches the 'a' in "plain". |
[^xyz] |
A negative character set. Matches any character not enclosed. For example, '[^abc]' matches the 'p' in "plain". |
[a-z] |
A range of characters. Matches any character in the specified range. For example, '[a-z]' matches any lowercase alphabetic character in the range 'a' through 'z'. |
[^a-z] |
A negative range characters. Matches any character not in the specified range. For example, '[^a-z]' matches any character not in the range 'a' through 'z'. |
\b |
Matches a word boundary, that is, the position between a word and a space. For example, 'er\b' matches the 'er' in "never" but not the 'er' in "verb". |
\B |
Matches a nonword boundary. 'er\B' matches the 'er' in "verb" but not the 'er' in "never". |
\cx |
Matches the control character indicated by x. For example, \cM matches a Control-M or carriage return character. The value ofx must be in the range of A-Z or a-z. If not, c is assumed to be a literal 'c' character. |
\d |
Matches a digit character. Equivalent to [0-9]. |
\D |
Matches a nondigit character. Equivalent to [^0-9]. |
\f |
Matches a form-feed character. Equivalent to \x0c and \cL. |
\n |
Matches a newline character. Equivalent to \x0a and \cJ. |
\r |
Matches a carriage return character. Equivalent to \x0d and \cM. |
\s |
Matches any white space character including space, tab, form-feed, and so on. Equivalent to [ \f\n\r\t\v]. |
\S |
Matches any non-white space character. Equivalent to [^ \f\n\r\t\v]. |
\t |
Matches a tab character. Equivalent to \x09 and \cI. |
\v |
Matches a vertical tab character. Equivalent to \x0b and \cK. |
\w |
Matches any word character including underscore. Equivalent to '[A-Za-z0-9_]'. |
\W |
Matches any nonword character. Equivalent to '[^A-Za-z0-9_]'. |
\xn |
Matches n, where n is a hexadecimal escape value. Hexadecimal escape values must be exactly two digits long. For example, '\x41' matches "A". '\x041' is equivalent to '\x04' & "1". Allows ASCII codes to be used in regular expressions. |
\num |
Matches num, where num is a positive integer. A reference back to captured matches. For example, '(.)\1' matches two consecutive identical characters. |
\n |
Identifies either an octal escape value or a backreference. If \n is preceded by at leastn captured subexpressions, n is a backreference. Otherwise, n is an octal escape value if n is an octal digit (0-7). |
\nm |
Identifies either an octal escape value or a backreference. If \nm is preceded by at leastnm captured subexpressions, nm is a backreference. If \nm is preceded by at leastn captures, n is a backreference followed by literal m. If neither of the preceding conditions exists, \nm matches octal escape valuenm when n and m are octal digits (0-7). |
\nml |
Matches octal escape value nml when n is an octal digit (0-3) andm and l are octal digits (0-7). |
\un |
Matches n, where n is a Unicode character expressed as four hexadecimal digits. For example, \u00A9 matches the copyright symbol (©). |
三.sed命令
sed的正则表达式用//括住。
1.sed文本的定位方法:
x |
x为一行号 |
x,y |
表示行号范围从x到y |
/pattern/ |
查询包含模式的行 |
/pattern/pattern/ |
查询包含两种模式的行 |
/pattern/,x |
在给定行号上查询包含模式的行 |
x,/pattern/ |
通过行号和模式查询匹配行 |
x,y! |
查询不包括指定行号x和y的行 |
2.sed编辑命令
命令 |
意思 |
p |
打印匹配行 |
= |
显示文件行号 |
a/ |
在定位行号后附加新文本信息 |
i/ |
在定位行号后插入新文本信息 |
d |
删除定位行 |
c/ |
用新文本替换定位文本 |
s |
使用替换模式替换相应模式 |
r |
从一个文件中都文本 |
w |
将文本写道一个文件 |
q |
第一个模式匹配完成以后退出或立即退出 |
l |
显示八进制ASCII代码等价的控制字符 |
{} |
在定位行执行的命令组 |
n |
从另一个文件中读文本下一行,并附加到下一行 |
g |
将模式2粘贴到/pattern n/ |
y |
传送字符 |
3.sed打印文件的第二行
sed -n ‘2p’ filename
4.sed打印文件的第一到三行
sed -n ‘1,2p’ filename
5.sed打印匹配test的行
sed -n ‘/test/p’ filename
6.sed打印匹配$的行
sed -n ‘/\$/p’ filename
7.sed打印最后一行:$是代表最后一行的特殊字符
sed -n ‘$p’ filename
8.sed脚本文件
#!/bin/sed –f “/company/” a/ “The suddenly it happen.”
将以上脚本保存为append.sed,使用chmod给予其可执行权限。使用append.sed filename运行。脚本的执行将会在filename文件中查找company,在匹配行的后一行中附加新文本,输出到屏幕上(不改变原文件)。
9.sed上例中如果将a\改为i\:
则为插入,在匹配行的前一行中附加新文本,输出到屏幕(不改变原文件)。
10.sed上例中如果将a\改为c\:
则为替换,匹配行被替换为新文本。
11.sed删除第一行
sed ‘1d’ filename
12.sed删除第一到第三行
sed ‘1,3d’ filename
13.sed删除最后一行
sed ‘$d’ filename
14.sed替换文本
sed ‘s/night/NIGHT/’ filename #将所有night替换为NIGHT
sed ‘s/night//’ filename #将night删除
15.sed输出到文件,w选项:
把第1到2行的内容输出到文件field中,不存在则创建。
sed ‘1,2w field’ filename
16.sed从文件读取,r选项:
把文件内容附加到匹配行company.之后
sed ‘/company./r sedex.txt’ filename
17.sed优势:
用户在获得不同格式的、带有各种奇形怪状格式控制符的文本,需要将它编成易读的文本时,就可以使用sed流编辑程序。另外,在重新处理具有比较固定格式的文本以生成新格式的文本时,也可以使用sed流编辑程序。
18.sed常见的一行命令集
命令 |
意思 |
‘s/\.$//g’ |
删除以句点为结尾行 |
‘-e/abcd/d’ |
删除包含abcd的行(疑为’/abcd/d’) |
‘s/[ ][ ]*/[ ]/g’ |
删除一个以上空格,用一个空格代替 |
‘s/^[ ][ ]*//g’ |
删除行首空格 |
‘s/\.[ ][ ]*/[]/g’ |
删除句点后跟两个或多个空格,用一个空格代替 |
‘s/^$/d’ |
删除空行(sh不支持d,但在ksh下支持) |
‘s/^.//g’ |
删除第一个字符 |
‘s/COL\(…\)//g’ |
删除COL以及其后的三个字母 |
‘s/^\///g’ |
删除开头的/ |
‘s/[ ]*/[ ]/g’ |
删除所有空格并用tab代替 |
‘s/^[ ]//g’ |
删除行首的一个tab |
‘s/^[ ]*//g’ |
删除行首的所有tab |
‘s/[ ]*//g’ |
删除所有tab |
‘s/[ ]*/[ ]/g’ |
删除所有tab并用一个空格代替 |
‘s/[ ][ ][ ][ ]*/[ ]/g’ |
每四个空格删除并使用一个tab代替 |
19.sed去掉字串变量前后的空格
str1=” 1234 “
str2=` echo ${str1} `
此时str2不含有前后的空格。
如果使用sed如下:
str2=”` echo ${str1} | sed ‘s/^[ ]*//g’| sed ‘s/[ ]*$//g’ `”
如果使用awk如下:
str2=”` echo $(str1) | awk ‘{print$1}’`”
或:
str2=”` echo $(str1) | sed ‘s/(^\s*) |(\s*$)//g’ `”
注:使用awk和sed的缘故是可以和前一次的操作一次性完成,而不必单独使用一条语句去除空格。例如下面第二个awk的作用就是去除空格:
TmpInf1="`echo $TmpInf | awk -F='{print $2}' | awk '{print $1}'`"
20.sed去除文件count中的前后的空格
tmp=`sed's/^ *//g' count | sed 's/ *$//g' `
则tmp为文件内容,不含有前后的空格。
21.sed提取最后一个目录名,
例如从../../etc/passwd或者/etc/passwd得到passwd
方法一:使用临时文件
#得到当前路径,输出到a文件
pwd >a
#读取a文件,过滤首字母/和尾字母/,将结果输出到b文件
sed 's/^\///g' a | sed ‘s/\/$//g’ >b
while fgrep \/ b
do
#读取b文件,过滤首字符串xxxx/,将结果输出到a文件
sed 's/^[a-zA-Z0-9]*\///g' b >a
#将a文件拷贝到b文件
cp -f a b
done
rm –f a
rm –f b
方法二:使用变量(优于文件形式)
c_path=`pwd`
#过滤首字母/和尾字母/
c_path=`echo$c_path | sed 's/^\///g' | sed‘s/\/$//g’ `
while [ `echo $c_path | grep -c '\/'`-gt 0 ]
do
c_path=`echo$c_path | sed 's/^[a-zA-Z0-9_.]*\///g'`
done
echo $cur_path
方法三:使用basename命令
c_path=`pwd`
c_path=`basename$c_path`
注:参数扩展见五.5
22.dirname或参数扩展提取目录名
例如从$0参数中提取运行的路径:从../../etc/passwd/得到../../etc,从/etc/passwd得到/etc
方法一:dirname
c_path=$0
c_path=`dirname$c_path`
注:如果没有路径,则c_path得到为单字符”.”。所以,判断是否在当前路径执行可以使用条件“-$c_path” = “-.”
方法二(参数扩展在基本sh下不支持):
c_path=$0
c_path=’${0%/*}’
注:如果没有路径,则c_path得到为文件名,即$0。所以,判断是否在当前路径执行可以使用条件 “-$c_path” = “-$0”
23.grep,sed获取文件的扩展名
例如从../../home/file.c得到c
方法一:
file=$1
#得到最后一级文件名 ,如file.c
file=`basename$file`
#如果文件名中不含有.,则表示没有后缀
if[ 1 -gt `echo $file | grep -c '\.'` ]; then
echo "no extion"
else
#过滤掉最后一个.以及之前的所有字符,得到扩展名
echo `echo $file | sed "s/.*\.//g" `
fi
方法二:(参数扩展在基本sh下不支持)
file=$1
#得到最后一级文件名 ,如file.c
file=`basename $file`
#从file的尾部开始删除匹配.*(一个.后跟若干字符)的最小部分并返回剩余部分
echo "${file%.*}"
四.awk命令
1.awk字段分隔符:
-F选项指定了字段分隔符为冒号
awk -F: ‘{print $1,$3}’ file
2.awk匹配模式
分为三类:
a) awk的关系表达式:
用来说明字段是否与要求符合。例如:$1==”char”、$2>20等等。
b) awk地正则表达式:
用//括住。规则与sed相同。
例如:
/^.$/ 匹配只有一个字符的行。
c) awk的BEGIN和END模式:
BEGIN模式意味着在读取第1行之前的匹配模式。它常用于初始化,例如设置分隔符、打印标题以及变量赋初值等。END模式是在处理完所有记录行以后的匹配模式。它常常用于输出结果。
3.awk“模式匹配-动作”
a)在每一行中匹配’foo’,若匹配则打印该行
awk ‘/foo/ {print $0}’ filename
b)在每一行中匹配第一个字段是否为’foo’, 若匹配则打印该行
awk ‘$1~/foo/ {print $0}’ filename
4.awk内部变量
(部分变量需要验证)
变量 |
含义 |
默认值 |
属性 |
ARGC |
命令行实参个数 |
- |
只读 |
ARGV |
命令行实参数组 |
- |
可读可写 |
FILENAME |
当前输入文件名 |
- |
只读 |
FNR |
当前文件中的记录数 |
- |
只读 |
FS |
输入字段分隔符 |
空白及制表符 |
可读可写 |
NF |
当前记录中的字段数 |
- |
只读 |
NR |
至今读取的记录数 |
- |
只读 |
OFMT |
数的输出格式 |
%.6g |
可读可写 |
OFS |
输出字段分隔符 |
空白 |
可读可写 |
ORS |
输出记录分隔符 |
换行符 |
可读可写 |
RS |
输入记录分隔符 |
换行符 |
可读可写 |
RSTART |
由match()匹配的第一个字符索引 |
- |
只读 |
RLENGTH |
由match()匹配的串的长度 |
- |
只读 |
SUBSEP |
下标分隔符 |
“\34” |
只读 |
CONVFMT |
数值的内部转换格式 |
%.6g |
可读可写 |
5.awk用户定义变量
用户自定义变量用以存放数据以及进行运算。
6.awk算术运算
算术运算在内部以浮点形式完成,也包含一般的加、减、乘、除、余和乘幂,运算符分别为”+”、”-“、”*”、”/”、”%”和”^”。
a) awk ‘$1==”Feb” {sum=$2+$3} END{printsum}’ filename
b) awk ‘$1==”ATOM” {a=a+$2;i=i+1}’ filename
c)
7.awk高级算符
++或者+=等等。
awk‘$1==”ATOM” {a+=$2;i++}’ filename
8.awk内部算术函数
函数名 |
返回值 |
cos(x) |
x的余弦值,x是弧度 |
exp(x) |
x的幂函数 |
int(x) |
x的整数部分 |
log() |
x的自然对数 |
rand() |
得出一个随机数,此随机数平均分布在0 和1 之间。这个值不会是0,也不会是1。 每次执行awk, rand 产生相同的随机数序列。 |
sin(x) |
x的正弦值,x是弧度 |
sqrt(x) |
x的平方根 |
srand(x) |
x是针对rand()的新的种子。设定产生随机数的开始点或seed 随机数种子为x。如果在第二次你设定相同的seed 值,你将再度得到相同序列的随机数如果省略参数x,则现在的日期时间会被当成seed。这个方法可使得随机数是真正不可预测的srand 的。 返回值(return value)是前次所设定的seed 值 |
9.awk内置函数
awk的字符串使用引号括起。通过连接常量、变量、数组元素、函数和其它表达式可以创建串表达式。
例如:打印第几号记录和一个冒号,然后打印文本行。
{printNR”:”$0}
函数名 |
返回值 |
gsub(r,x) |
在当前记录中,用s替换r,返回替换数 |
gsub(r,s,t) |
在串t中,用s替换r,返回替换数 |
index(s,t) |
返回s串中t的位置,不出现时为0 |
length(s) |
返回s的长度 |
match(s,r) |
返回r在s中出现的位置,不出现时为0 |
split(s,a) |
针对FS把s分成数组a,返回字段数 |
split(s,a,r) |
针对r把s分成数组a,返回字段数 |
sprintf(fmt,expr_list) |
根据格式串fmt返回经过格式编排的expr_list |
sub(r,s) |
在当前记录中把第一个r替换成s,返回替换数 |
sub(r,s,t) |
在t中把第一个r替换成s,返回替换数 |
substr(s,p) |
返回从位置p开始的s的后缀 |
substr(s,p,n) |
返回从位置p开始长度为n的s子串 注: p最小为1,当p为0时,p被置为1; n个字符包括p所在字符。 举例: echo "abced" | awk '{print substr($1,2,2)}' 返回 bc |
system(cmd) |
执行命令并返回出口状态 |
toupper(s) |
将输入参数s中的字符全部转换为大写字符并返回转换后的字符串 |
tolower(s) |
将输入参数s中的字符全部转换为小写字符并返回转换后的字符串 |
close( expr ) |
关闭由expr表示的文件或管道,文件或管道可能被print、printf语句或调用内建函数getline打开。如果成功,函数返回0,否则返回非0值 |
getline |
这个内建函数将$0设置为当前输入文件的下一个输入记录,getline < file将用从file中获得下一条记录修改$0的值,getline x用下一行的内容替换变量x,而$0仍然是当前行的内容。但下一次返回的将是下下一行的内容。cmd | getline将从管道中获得cmd命令的输出。如果成功,getline返回1,遇到文件结尾,getline返回0,出错返回-1。 |
|
|
10.awk的自定义函数
格式:
function func_name(arg_list)
{
}
例如:
将下列代码保存在awk_pro文件中,调用echo5 | awk –f awk_pro,将得到输出:5!is120。
functionfact(n)
{
if(n<=1)
return 1
else
return n*fact(n-1)
}
{print$1”!is” fact($1)}
数组实参可以通过应用传递,所以针对该函数有可能改变数组元素或创建一个新元素。标量实参将用值传递,形式参数是局部变量,但其它变量都是全局量。
11.awk的“下一”语句:
next语句 、nextfile 语句 、exit 语句
next语句强迫awk立刻定制处理目前的记录而继续下一个记录。
nextfile类似next,它强迫awk立刻定制处理目前的数据文件。
exit语句会使得awk程序停止执行而跳出。如果END出现,它会去执行END的动作。
12.awk中的字符串相加:
str3为str + str2 + str
str="hello""world"
str2="----- "
str3=str str2 str
13.awk的逻辑运算符
表达式 |
含义 |
x==y |
x等于y时为真 |
x>y |
x大于y时为真 |
x>=y |
x大于或等于y时为真 |
x<y |
x小于y时为真 |
x<=y |
x小于或等于y时为真 |
x!=y |
x不等于y时为真 |
x~y |
x包含y时为真 |
x!~y |
x不包含y时为真 |
|
|
例如:
awk'$2~"aaa" {print $0}' filename
14.awk的逻辑与||、逻辑或&&
awk '$2=="bbb" ||$2=="ccc" {print $0}' filename
awk '/2400/ && /foo/'BBS-list
awk '/2400/ || /foo/' BBS-list
awk '!/foo/' BBS-list
15.awk的FS、OFS和ORS使用:
以’|’为分隔符输出各个域
awk‘BEGIN{OFS=”|”}{print $1,$2,$3,$4}’ filename
awk 'BEGIN {OFS=";";ORS="\n\n"} {print $1, $2}' filename
awk'BEGIN {FS=","}; {print $2}'
16.awk的sprintf函数的使用
sprintf格式化字符串
print sprintf("%03d",2);
17.awk的重定向,输出到文件:
可以使用>或者>>
print "This is a test" >"fff.txt"
18.awk删除文件的第一行
awk ‘{ if(NR % 2 == 1) printf “%s”, $0 ’
19.awk删除输入行中特定行的换行字符
例如:删除奇数行的换行字符
awk '
{
if (NR % 2 == 1)
printf "%s",$0 ;
else
print $0
}'
20.awk获取输入行中,域的最大个数
awk '{if (NF > max) max = NF}END {print max}'
21.awk输出一行超过80个字符的每一行
awk 'length($0) > 80'
22.awk输出至少一个域的所有行。可用来将一个文档里的所有空白行删除
awk '{if (NF > 0) print}'
23.awk输出范围在0到100 之间的7个随机数
awk 'BEGIN {for (i = 1; i <= 7;i++)
print int(101 * rand())}'
24.awk将所有用户的login名称依照字母的顺序输出
awk 'BEGIN {FS = ":"}{print $1 | "sort"}' /etc/passwd
25.awk将一个文档的总行数输出
awk '{nlines++} END {printnlines}'
或awk 'END {print NR}'
26.awk输出文档的内容时会在每行的最前面输出行号它的功能与'cat-n' 类似
awk '{print NR,$0}'
27.awk自定义函数的例子一: 第一个域与第二个域的平方和
awk ‘{print "sum=",SquareSum($1,$2)}
function SquareSum(x,y) {
sum=x*x+y*y
return sum
}’
28.awk的split、数组、注释
test.awk文件:
#!/bin/awk-f
BEGIN{
record="123#456#789"
num=split(record,myarray,"#")
}
END{
for(i=1;i<=num;i++)
{
print myarray[i] # print the element of array
}
}
调用:
./test.awk /dev/null
输出:
123
456
789
五.其它命令
1.eval命令:可用于动态生成和执行代码
foo=10
x=foo
eval y=’$’$x
echo $y
输入10,即eval y=’$’$x被解释为y=$foo,即y=10。
nDay1="111"
nDay2="222"
nDay3="333"
# 遍历变量nDay1 ...nDay3,打印其值
for i in 1 2 3
do
n=$i
eval nVar='$nDay'$i
echo $nVar
done
2.exit n:退出
0代表成功,1-125代表出错代码,128以上引发一个信号。
3.export命令:
把参数变量名导出到子shell里,使之成为子shell的环境变量。
存在a.sh和b.sh两个shell脚本,在a.sh中调用b.sh,a.sh使用export输出的变量将成为b.sh的环境变量。
使用set –a 或者set–allexport将把在它之后声明的任何变量导出为环境变量。
4.shift命令:
把所有参数变量向下移动一个位置。
while[ "$1" != "" ];
do
echo "$1"
shift
done
5.参数扩展:
tmp_1="1111"
tmp_2="2222"
fori in 1 2
do
eval tmp='$'tmp_${i}
echo $tmp
done
其中,tmp_${i}为参数扩展的应用。常见参数扩展替换见下表:
参数扩展 |
说明 |
${param:-default} |
若param空,则把它设为default的值 |
${#param} |
给出param的长度 |
${param%word} |
从param的尾部开始删除匹配word的最小部分并返回剩余部分(sh不支持,ksh支持) |
${param%%word} |
从param的尾部开始删除匹配word的最大部分并返回剩余部分(sh不支持,ksh支持) |
${param#word} |
从param的头部开始删除匹配word的最小部分并返回剩余部分(sh不支持,ksh支持) |
${param##word} |
从param的头部开始删除匹配word的最大部分并返回剩余部分(sh不支持,ksh支持) |
例:将某个文件夹下所有gif文件通过cjpeg程序转换为jpeg文件。
forimage in *.gif
do
cjpeg $image > $(image%%gif)jpg
done
例如:
FILE_NAME=${0##*/} 程序的文件名(不带路径)
BASE_DIR=${0%/*} 程序的路径
其它实例可参见三.22
6.<<即时文档
开始是”<<”,然后是特殊字符序列,该序列将在文档结尾再次出项。注意,结束的!FUNKY!最好顶格,前后不要留空格。
cat<<!FUNKY!
hello
thisis a here
!FUNKY!
7.sh调试选项
使用”-o”设置选项,使用”+o”取消设置。
命令行选项 |
set命令选项 |
说明 |
sh -n <script> |
set -o noexec |
只检查语法错误,不执行命令 |
set -n |
||
sh -v <script> |
set -o verbose |
在执行命令之前回显它们 |
set -v |
||
sh -x <script> |
set -v xtrace |
在处理完命令行之后回显它们 |
set -x |
||
set -o nounset |
如果使用了未定义变量 就给出一条出错信息 |
|
|
||
|
|
|
8.time命令测试一个程序执行时间
time test.sh
9.expr命令
x=`expr 10 + 10`
x=`expr $x + 10`
x=`expr $ \* 2`
注:加号两边必须有空格,乘号必须有转义符。
10.if语句判断变量是否为某个值(防止空串)
因为数值的比较操作数不能为空,所以如果变量可能为空,且仅仅是进行等于或者不等于的比较操作时,则应转化为:
if[ "-$VarName" = "-5" ]; then
而不要使用 if [ $VarName –eq 5 ]; then
数值测试有如下比较符:
-eq、-ne、-gt、-lt、-le、-ge
对于-gt 、-lt、 -le 、 -ge等其他比较符,有以下两种方法:
a) 先判断是否为空,然后再做比较(适用于确定变量为数字的情况)
b) 先判断为数字,然后再做比较(适用于不确定变量为数字的情况)。
if["-$VarName" != "-" ]; then
if[ $VarName –gt 5 ]; then
......
或者
is_integer$VarName
if[ $? = 0 ] ; then
if[ $VarName –gt 5 ]; then
......
注:is_integer函数判断一个串是否是整数,见章节“六.31iTELLIN示例十五”
11.nm命令察看一下xxx.o文件中是否有多个相同名字的函数
12.ps、grep和awk显示属于某个用户的所有进程(并杀死)
方法一:ps +grep
list=ps -e -f | grep USRID
方法二:ps -u
list=`ps-u $LOGNAME`
方法三(推荐)ps + grep + awk:
list=`ps -u$LOGNAME|grep -v csh|grep -v PID|awk '{print $1}'`
说明:
grep –v csh 避免杀死本sh程序(也有可能遗漏一些sh程序)
grep –v PID 由于ps显示有顶行标题,此句可以过滤此行
杀死程序:
for i in $list
do
kill -9 $i
done
13.touch命令
创建以当前时间为文件名的文件:
touchlogfile.`date ’+%y%m%d.%H:%M’`
创建修改时间为1996年1月2日03:04的文件:
touch 0102030496 file
注:用两位数字表示年份,2003写作03,1996写作96
14.touch与make联合使用强制编译
touch*.c
make
make将发现所有的.c文件都比相应的.o文件具有更新的版本,从而重新编译。
15.dd命令传送文件
使用 dd指令,可以把一个文件转换成另一个文件,也可以选择文件的一部份传输,在传输的数据中,也可以交换字节顺序。
dd if=/dev/fd0 of=/temp/save skip=5count=6 bs=5k
上面的指令″/dev/fd0″ 是指电脑上的软盘,″skip=n″代表在复制到输出文件之前,跳过输入文件上的几个记录。″bs=n″则 表示设置输入输出字节块长度,用 k 表示 1024 字节。″count=n″ 只复制输入记录的指定数,所以上述指令跳过25k字节,拷贝30k字节。
16.talk命令
与本机用户交谈
talk user_name
与在ccsun22主机上的用户交谈
talk user_name@ccsun22
17.ps命令
-u 〈username〉选项显示指定用户的讯息。
-t 〈ttynamt〉选项显示指定终端有关的进程讯息。
而ps -elf指令则提供了需有F、S、C、PRI、NI、TIME字段的使用讯息:
F是指示进程位置,20表示在内存,0表示交换在盘上, 31是系统进程。
S是指示进程状态,睡眠还是正在运行。
C是进程占有CPU的百分率
TIME是花费CPU的总时间。
PRI是进程当前优先数
NI是进程的nice (ADM)菜单
18.rm指令
-i 征求确认后才会删除
-r <目录> 删除该目录及该目录之下的所有档案
-rf <目录> 同上,但不会先徵求确认
19.find命令
在/usr/ice下查找hihi.c文件或目录,找到后在屏幕上显示
find /usr/ice -name hihi.c –print
20.df命令
显示可使用之档案储存空间及档案数目
df
21.rusers命令
rusers命令列出远程机器上的用户
列出网络上各台主机的用户
rusers
列出sco-gfep主机上的用户
rusers -l sco-gfep
-l选项以who的格式给出一个表(较详细)
22.cal命令
显示2003年年历
cal 2003
显示本月月历
cal
显示2003年九月月历
cal 09 2003
23.tty命令
显示目前所用终端机名称
24.banner命令
放大显示字符(个数不超过10个):
banner “1234”
25.find命令
find . -namehello -print 寻找目前目录及所有的子目录内叫hello的文件
find . -size+2000m -print 找出大小超过2000 bytes的档案
find /tmp -userb1234567 -print 在/tmp下属於b1234567的档案
find . -name'*.c' -exec rm {} \; 删除所有的.c档
find . –mtime +6 –print 找出修改时间在6天前的档案
find . -ctime +7 -print 找出七天内未被更动的档案
26.cut命令
分割文件每一行选择的字段。
cut -c list [ file ... ]
cut -f list [ -d delim ] [ -s ] [ file ... ]
选项
-c list 此选项(无空格)确定字符位置list是以逗号分割的字段号码,说明域号的整数表(递增次序),可以用-表示范围,(c表示char):
-c1,4,7 字符1,4和7
-c1-8,9 字符1到3和8
-c-5,10 字符1到5和10
-c3- 字符3到最后
-f list 此选项确定字段列表,以定界符分隔。没有字段定界符的行将完整传送,(f表示field)
-f 1,7 只拷贝第1和第7个字段。
-f 1-3 只拷贝第1到第3个字段。
-dchar 紧跟-d的字符char是字段定界符,缺省值为tab,对shell有特殊意义的字符必须用引号引起来。
-d”“ 使用一个空格作为定界符。(d表示define)
例子:
获取当前注册名
whoam i | cut -f1 -d" "
将用户标识符映射成名称
cut -d: -f1,5 /etc/passwd
显示12 34
echo"12 34 567 89 0" | cut -d" " -f 1-2
显示12345
echo“12345678” | cut –c 1-5
诊断:
I“ERROR: line too long”
一行不能超过1023个字符或字段。
27.paste命令
合并几个文件中的相同行或同一文件其后的相同行。
paste[ -s ] [ -d list ] file ...
paste将file1 和file2 等的对应行连接起来,将每个文件看成是列或表的各列而将他们水平的粘贴在一起(平行合并)。
选项:
-d 无此选项时,文件中的每个换行符都由tab字符取代,但最后一个文件须除外(或在-s选项时最后一行除外)。此选项允许由list中一个或多个备用字符来替换tab字符(见下)。
list 代替tab成为行连接字符的一个或几个字符。即-d后面的list中的字符将依次作为行连接字符的一个或几个字符。如果是两个或多个文件合并,则作为每个文件行之间的连接字符。如果是一个文件自身合并,则作为每行的连接字符。List可包括:\n(新行)、\t(tab)、\\(反斜杠)、\0(空行),但不能为null字符。
-s 合并后续行而不是各文件中的行。用tab作为连接符。
- 可代替文件名,以从标准行中读入一行(不给出提示)。
例子:
文件1.txt内容如下
1 2 3 4 5 6
a b c d e f
文件2.txt内容如下
11 22 33 44 55 66
aa bb cc dd ee ff
连接1.txt和2.txt的各行,以tab作为行连接字符
paste 1.txt 2.txt
输出:
1 2 3 4 5 6 11 22 33 44 55 66
a b c d e f aa bb cc dd ee ff
连接1.txt各行,以空格作为连接字符
1 2 3 4 5 6 a b c d e f
在一列中列出目录
ls | paste –
在四列中列出目录
ls | paste - - - -
将成对行合并成行
paste -d “\t\n” –s 1.txt
诊断:
“linetoo long:”
输出字符限制在511个
“toomany files:”
除非用-s选择,否则最多只能指定12个输入文件。
28.rm命令
rm[-f][-i] file
rm [-r[-f][-i] dirname …[file…]
rmdir[-p][-s] dirname
rm删除一个目录中的一个或多个文件。
选项
-f 此选项删除所有的在目录中的文件(不管是否有无写保护),而不对用户进行提示。在有写保护的目录中不能对文件进行删除,但不显示任何信息。
-r 此选项删除参数中列出的所有目录和子目录。
例子:
删除目录mend_check_dir并且不回显
rm-fr $INSTALL_PATH/mend_check_dir >/dev/null 2>&1
29.mkdir命令
mkdir在方式777下建立目录(方式可用umask更改).
Mkdir[-mmode][-] dirname ...
选项:
-m 此选项允许用户指定新目录使用的方式.
-p 使用此选项,可以建立一个名为dirname且在父辈目录中不存在的目录。
例如:
建立目录dir1/dir2,即使dir1在当前目录中不存在。
mkdir -p dir1/dir2
30.cat命令
连接和显示文件。
cat[-u][-s][-v][-t][-e] file ...
cat按顺序读每个file,且将它写到标准输出上。
如果未给出文件名,或者遇到变元,cat将从标准输入文件上读。
例如:
打印file到终端
cat file
连接file1和file2,且把结果写入到file3
cat file1 file2 > file3
31.pkgadd命令
将软件包传送给系统。
pkgadd[-d device] [-r response][-n][-a admin]
[pkginst1 [pkginst2[…]]]
pkgadd将软件包的内容从安装它的分布介质或目录转送到系统。若没有使用-d选项,pkgadd在缺省的假脱机目录中查找该报(/var/spool/pkg)。若使用-s选项,就将该包读到假脱机目录而不安装它。
选项:
-d 从device安装或拷贝一个包。device可以是到目录的完整路径名。
pkginst 说明被安装的包实例或实例列表记号all可用来查阅在源介质上的所有可用包。
32.groupadd和mkgroup命令
把新的小组定义添加(建立)给系统
groupadd[-g gid[-0]] groupname
选项:
-g gid 对新组的组id。此组id必须是非负的十进制整数,此整数小于在<param.h>主文件中定义的MAXUID。
例如:
groupadd -g $GroupID$GroupName
注:HP和SUN平台使用“groupadd”命令。IBM平台使用“mkgroup”命令。
增加用户的命令见“五.54 useradd和mkuser命令”
33.ln命令
建立硬链或符号链。
ln[-fs] filename [linkname]
把filename连接到linkname。其中filename可以是一个或多个文件名,用户可建立多个file连接到linkname。
选项:
-s ln将建立一个象征性连接。
34.su命令
成为特殊用户或其他用户。
su[-][name[arg ......]]
su允许一个用户在未注销时成为另一个用户。
选项:
- 完成一个完全的注册。删除除TERM之外的环境中的所有变量,将USER设置为name,HOME和SHELL从被替换用户的口令文件中获得,将PATH设置为:/usr/ucb:/bin:/usr/bin,将目录更改为name的本地目录,并告诉shell读name的.login或.profile文件。
-f 完成一个快速的su。如果与C shell一起使用,将阻止C shell去读name的.cshrc文件,如果与Bourne shell一起使用,将不支持文件名生成。
例如:
执行ln命令和成为sms用户:
su- sms -c "ln -s $SCP_HOME/sms v20"
35.setenv命令
设置环境变量
例子:
设置环境变量INFORMIXDIR的值为$INFORMIX_HOME
setenv INFORMIXDIR "$INFORMIX_HOME"
36.repeat命令
用来执行只有一个固定次数的命令。
例子:
在屏幕上显示连字符(-)80次
repeat80 echo ‘-‘
37.getopts命令
用来解析命令选项。
用法:
getoptsoptstring name[arg...]
说明:
optstring必须包含使用getopts将识别的选项字母,如果字母右跟随一个冒号,则选项期望有一个变元或变元组,并由空格分开。
每一次调用时,getopts把下一个选项放入shell变量Name中,且在shell变量OPTIND中处理下一个变元的索引;无论是调用shell和sehll过程,OPTIND初始化为1。
当一个选项需要一个选项变元,getopts把它放置在shell变量OPTARG中。
如果遇到一个非法选项,将把?放入name中。
当遇到选项结束时,getopts将带着一个非0出口状态退出;专用选项—-可以用来确定选项结束的边界。
在缺省状态下,getopts解析位置参数,如果getopts命令行中给出变元(arg...)则getopts将解析它们。
实例:
下述的shell程序框架显示如何处理选项a或b及选项o的命令变元的:
while getoptsabo:c OPTION
do
case $OPTION in
a|b)
FLAG=$OPTION
;;
o)
ORAG=$OPTARG
;;
\?)
echo $USAGE
exit 2
;;
esac
done
shift `expr$OPTIND – 1`
此代码接收下述任意等价命令:
cmd –a –b -o123file
cmd –a –b --–o123 file #将忽略”—-“以后的选项
cmd –ab–o”xxx” file
cmd –o”xxx” –a–b file
38.sort命令
把所有命名文件一起排序和合并,并把结果写到标准输出上。如果使用’-‘作为文件名或者没有命名输入文件,则读标准输入。
简单用法:
sort [-dfiMnr][files]
下列选项重写缺省的排序规则:
-d ”Dictionary”排序,在比较时只人士字母、数位和空格
-f 将下档字符转化成上档字符
-i 忽略不可打印的字符
38.kill命令和trap命令
操作系统可以向脚本或命令发出消息,告知它们某个事件的发生,这些事件通常是内存错误、访问权限问题或某个用户试图停止你的进程等等。这些事件称之为信号。它们中的一些可以被shell脚本捕获。
如信号2就表示来自键盘的中断信号,当按下CTRL-C时触发此信号。信号2的名字是SIGINT, 2是信号的号码。
注:如果想查看所有信号,可以使用kill -l命令列出所有信号。
发送信号可以使用如下格式:
kill [-signal no: | signal name ] process ID
在脚本捕获信号的命令的形式如下:
trap command signal(s)
command是捕获到信号后用来处理的函数,需要使用引号扩起。
例如:
trap "" 2 3 忽略信号2和3
trap"commands" 2 3 如果捕捉到信号2或2,则执行相应的commands命令
下面是一个脚本例子,用trap捕获signal 2:
#!/bin/sh
# usetrap to catch signal 2 (CTRL-C)
# settrap
trap"catch_signal_two" 2
LOOP=0
# catchsignal 2
catch_signal_two()
{
echo "You just hit <CTRL-C>, atnumber $LOOP"
echo "I will now exit"
exit 1
}
# loop
echo"Loop start, you can use CTRL-C toend."
while :
do
LOOP=`expr $LOOP+ 1 `
echo $LOOP
done
注:当在catch_signal_2函数中不使用exit 1时,执行完两个echo命令后,while循环还会继续执行。
39.fsck命令
检查和修复文件系统。
例如:
fsck –y #不需要确认直接检查和修复文件系统。
40.useradd和mkuser命令
为组添加用户。
useradd -d <HOME目录>-g <所属组> -s/usr/bin/csh -m <用户名>
例如:
如在SUN下创建smpsys用户:
useradd-d /home/smpsys -g sms -s /bin/csh -m smpsys
注:HP和SUN平台用useradd命令,IBM平台使用“mkuser”命令,命令格式为:
mkuser pgrp=<所属组> home=<HOME目录> shell=/usr/bin/csh <用户名>
六.杂项
1.setenv PATH和set path =(....)
解答:set path仅仅作用于当前的shell,setenv也对子shell起作用。
2.awk中输出单引号
echo "a b c" |awk '{print $1 单引号 $2 单引号 $3}'
我要给b加单引号,输出成下面格式:
a 'b' c
解答:
echo"a b c"|awk '{printf("%s %c%s%c %s\n",$1,39,$2,39,$3)}'
3.awk或read找出文件行字符数大于80的行
方法一:使用awk的NR
awk '
{
line_len=length
if (line_len >80)
print NR":"line_len
}'<$1
注:若length函数不加参数,则表示处理当前行
方法二:使用read,循环处理
while read line
do
count=`echo $line|wc -C`
countnum=`expr $count - 1`
if [$countnum -gt 80 ]; then
echo "$linecount: ($countnum) $line"
fi
done < $1
4.shell脚本程序中的用户切换:
切换到另一个用户,执行几个操作然后退出来,整个过程不退出脚本执行
解答:
su -bin -c command arguments
5.shell中删除文件且不显示输出信息和出错信息
解答;
rm ${HOME}/bin/.filesize > /dev/null 2>&1
>为重定向符号,2>&1表示标准错误输出定向导标准输出,又由于标准输出被定向到/dev/null,所以两者都被定向导/dev/null。
6.shell变量赋初值时存在特殊字符
以下程序无法正常运行:
name=”test”
pwd=”$google”
ftp -in $1 <<FTP_CMD
user $name $pwd
ls
bye
FTP_CMD
原因是$是特殊字符。解决方法,使用单引号’
pwd=’$google’
建议:字符串赋初值均采用单引号’
7.sed的参数串中存在/特殊字符
需要把 /export/home/mywork 转换为\/export\/home\/mywork
先构造转化如下:
echo"/export/home/mywork" | sed "s/\//\\\//g"
在bsh和ksh下不能运行,在csh下可正常运行。
原因是对sed的表达式的解析不能完成。解决方法,使用单引号’
echo"/export/home/mywork" | sed 's/\//\\\//g'
建议:对sed的表达式均采用单引号’
8.find在一个目录下找包含一个字符串的所有文件
find ./ -name "*.sh" | xargsgrep "set"
find . -name "*.sh" -exec grep-l "set" {} \;
9.shell中确定一个文件的存在,文件ins_billdb
if [ ! -f $INSTALL_PATH/ins_billdb ]; then
10.read的参数与实际域的个数不同
read只读取一行的文本,当read的参数多于实际域个数时,多余的参数为空,不会读取到下一行;当read的参数少于实际域个数时,最后一个参数的值包含剩下所有域。
例如:
文件内容:1 2
使用 read arg1 arg2 arg3读取时,arg3为空。
使用 read arg1读取时, arg1为1 2
11.grep获取主机名和IP地址
方法一.从host文件获取
##############################################
# name : get_host_info
# description: get host name and ip address
# input: N/A
# output: HostName , HostIP
# return: 0 –- get successfuly
# others -- get failure
##############################################
get_host_info()
{
HostName=`hostname`
#过滤纯注释行(以#开头或者以 空格+#开头的行),
#然后过滤127.0.0.1,获取本机的ip地址
HostIP=`cat/etc/hosts|grep -v "^[ ]*\#" | grep -v 127.0.0.1 | grep $HostName |awk '{print $1}'`
if [ $? -ne 0 ];then
echo "Error! can't get Host IP"
return 1
fi
if[ $? –eq 0 ]; then
return0;
else
return1;
}
方法二.从ifconfig获取
##############################################
# name : get_host_info
# description: get host name and ip address
# input: N/A
# output: HostName , HostIP
# return: 0 –- get successfuly
# others -- get failure
##############################################
get_host_info()
{
#得到ip地址所在行
ip=`ifconfig-a | grep [1-9][0-9]\{0,2\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" |awk '{print $2}'`
#提取ip地址
ip=`echo$ip | awk '{print $2}'`
is_ip_address$ip
if[ $? –eq 0 ]; then
return0;
else
return1;
}
注:is_ip_address函数见“六.13 确定字符串是否是ip地址”
12.grep确定变量不是数字
见“31.iTELLIN示例十五:判断一个字符串是否是整数”
13.确定字符串是否是ip地址
##############################################
# name : is_ip_address
# description: judge whether the string
# is a ip address
# input: string
# return: 0 –- is ip address
# others -- not ip address
##############################################
is_ip_address()
{
TmpValue=$1
nCount=`echo "$TmpValue" |grep–c [1-9][0-9]\{0,2\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'`
if [ 1 –eq $nCount ]; then
# remove the char ‘.’ from $TmpValue
TmpValue="`echo$TmpValue | sed 's/\./ /' | sed 's/\./ /' | sed 's/\./ /'`"
for i in$TmpValue
do
if [ "$i" -gt 255 ]; then
#echo"Error! $TmpValue is not a IP address!"
return1
fi
done
return 0
else
#echo "Error! $TmpName is not a IPaddress!"
return 1
fi
}
14.grep列出某个用户的所有进程:
USER_NAME
ps-ef | grep "^[ ]*$USER_ NAME"
grep查找以0到多个空格和用户名开头的行。
15.grep和awk列出某个目录下的一级子目录
DIR=$1
ls -l $DIR | grep '^[ ]*d\.*' | awk'{print $9}'
ls –l列表的第九项为文件名。如果不加入awk的过滤,则打印子文件夹详细信息。
16.用printf将一个数打印成逗号分隔的形式
以下为awk中的程序。
/*
函数名: int_add_comma
功能 : 将传入的整数转化为每N位加一个逗号形式的字符串。
参数 :
num : 需要被转化的整数
ret : 存贮转化以后的字符串,空间由调用者提供
N : 间隔位数
返回值:
0 --转换正常,结果存放在ret中。
-1 --转换失败,传入参数不符合要求。
例子:
调用:
char buf[10] = "";
nret = int_add_comma(1234,buf,3);
返回:
nret=1
buf="1,234"
*/
intint_add_comma(long num,char *ret, int N)
{
char buf[10] = "";
char *p, *q;
int i, j, ncount, nleft;
if (ret == NULL || N <= 0 )
return -1;
sprintf(buf, "%u", num);
ncount = strlen(buf) / N;
nleft = strlen(buf) % N;
for (p=buf,q=ret,i=0; i<nleft; i++)
*q++ = *p++;
if (nleft > 0)
*q++ = ',';
for (i=0; i<ncount; i++)
{
for (j=0; j<N; j++)
*q++ = *p++;
if (i < ncount-1)
*q++ = ',';
}
*q = '\0';
return 0;
}
17.在ksh中使用数组
a) 初始化数组函数:
#!/usr/bin/ksh
sub_init_var()
{
HOST_NAME[0]="" #Save var name array
HOST_VALUE[0]="" #Save var value array
HOST_COMMENTS[0]="" #Save var commentS array
HOST_TYPE[0]="" #Save var type array
HOST_COUNT=0 #Save array element Count
}
注:其中HOST_NAME等为数组,HOST_COUNT为全局的HOST个数,虽然是在sub_init_var中声明,但是变量作用域是全局的。
b) 循环给数组赋值,取数组元素个数,访问数组元素、数组元素长度
#!/bin/ksh
datalist=`ls -l| awk '{print $9}'`
index=0
for j in $datalist
do
datalist[$index]=$j
let index+=1 #或者 index=`expr $index + 1`
done
index=0
# ${#datalist[@]}数组元素个数
while [ $index -lt ${#datalist[@]} ]
do
# ${datalist[index]}数组元素
# ${#datalist[index]}数组元素长度
echo “${datalist[index]} length is ${#datalist[index]}
let index+=1 #或者 index=`expr $index + 1`
done
18.从文件中读取参数:
文件存放格式:
[HOST]
g_Node1_Host itellin1 #Node1 host name
g_Node2_Host itellin2 #Node2 host name
g_ClusterName itellin #Clustername
[DEVICE]
SMC_IP10.76.137.101 #Service Manager CenterIP
SMC_LISTEN_PORT5060 #Service Manager Center Listenportal
Set_FireWallNO #Portal FireWall Set
FireWallIP 10.76.137.156 #Portal FireWallLogic host IP
......
文件读取函数:
###########################################################
#函数:read_var
#目的:从全局配置文件中读取变量值
#方法:
#输入:全局配置文件名
#输出:全局配置文件中的变量值
#限制:
###########################################################
read_var()
{
#参数个数是否是一个
if [ $# -ne 1 ]; then
echo "Error usage!"
exit 1
fi
CfgFile=$1
#参数所代表的配置文件是否存在
if [! -f $CfgFile ]; then
sub_echo_log "File $CfgFile doesnot exist!"
exit 1
fi
echo "\nread configuring file,wait..."
#读取 NAME VALUE COMMENT
while read VarName VarValue VarTemp
do
#如果是读取 HOST 段的信息
if ["1" -eq "`echo "$VarName" | grep -c '\[HOST\]'`"]; then
while read VarName VarValue VarTemp
do
if [ "-$VarName" ="-" ]; then
continue
#如果是 [xxxx]形式的文本
elif ["1" -eq "`echo "$VarName" | grep -c '\[.*\]'`" ];then
break
else
HOST_NAME[HOST_COUNT]="$VarName"
#如果是注释(以#开头)
if ["1" -eq "`echo "$VarValue" | grep -c '^#.*'`" ];then
HOST_VALUE[HOST_COUNT]=""
HOST_COMME[HOST_COUNT]=""
else
HOST_VALUE[HOST_COUNT]="$VarValue"
HOST_COMME[HOST_COUNT]="$VarTemp"
fi
((HOST_COUNT=HOST_COUNT+1))
fi
done
fi
#如果是读取 DEIVCE 段的信息
#格式同HOST段的读取
......
continue
done < $CfgFile
sub_echo_log "read configuring file$SrcFile ok"
}
19.包含其它脚本文件
使用操作符.包含另一个脚本文件package.cfg:
. $INSTALL_PATH/package.cfg
其中package.cfg文件内容如下:
#压缩文件名
SCP_CMPD_FILE="iSCP_INSTALL.tar.Z"
SMP_CMPD_FILE="iSMP_INSTALL.tar.Z"
MML_CMPD_FILE="MMLSERVER_install.tar.Z"
WMAS_CMPD_FILE1="WmasBin.tar.Z"
WMAS_CMPD_FILE2="WmasRunEnv.tar.Z"
......
20.初始化一个临时文件供使用
##############################################
# name : sub_initfile
# description: initialize a temp file for use
# input: temp file name
# return: N/A
##############################################
sub_initfile()
{
FileName="$*"
if [ -f $FileName ]; then
rm -f $FileName
fi
touch $FileName
chmod 666 $FileName
}
初始化一个临时文件,将df输出结果写入临时文件,显示临时文件内容
sub_initfile $TmpFile
df -k > $TmpFile
if [ "$?" != "0" ];then
sub_echo_log "Error! Check filesystem failure!"
exit 1
fi
echo "\n*************** file systemBEGIN ***************\n"
cat "$TmpFile"
echo "\n** ************* file systemEND ***************\n"
21.分解字符串
字符串为"setshmsys:shminfo_shmmax=256000000",为函数参数
分解代码如下:
system_set_value()
{
TmpInf=$*
#得到TmpInf1=”256000000”
TmpInf1="`echo $TmpInf | awk-F= '{print $2}' | awk '{print $1}'`"
#得到TmpInf=”set shmsys:shminfo_shmmax”
TmpInf="`echo $TmpInf | awk-F= '{print $1}'`"
#得到TmpInf2=”shminfo_shmmax”
TmpInf2="`echo $TmpInf | awk-F: '{print $2}' | awk '{print $1}'`"
#得到TmpInf=”set shmsys”
TmpInf="`echo $TmpInf | awk-F: '{print $1}'`"
#得到TmpInf3=” shmsys”
TmpInf3="`echo $TmpInf | awk'{print $2}'`"
#得到TmpInf4=”set”
TmpInf4="`echo $TmpInf | awk'{print $1}'`"
}
22.替换配置文件中的值
配置文件中的配置参数被设置参数取代。
如配置文件为$TmpFile,里面有一行为
setshmsys:shminfo_shmmax=256000000
shell代码中的缺省配置为
setshmsys:shminfo_shmmax=199000000
在得到用户许可以后,使用缺省配置代替$TmpFile中的值,代码如下:
#从缺省配置行得到变量TmpInf1,TmpInf2,TmpInf3,TmpInf4(见上例)
SetInf="setshmsys:shminfo_shmmax=256000000"
system_set_value $SetInf
#得到配置文件的拷贝
cat "/etc/system" > $TmpFile
#如果配置文件中有相应的配置行
if ["1" -eq `cat $TmpFile | grep -v "^[ ]*\*" | grep $TmpInf4 | grep $TmpInf3 | grep -c $TmpInf2`]; then
#得到配置文件的配置行
MyInf=`cat$TmpFile | grep -v "^[ ]*\*"| grep $TmpInf4 | grep $TmpInf3 | grep $TmpInf2`
#保存缺省配置的数值
OldTmpInf1="$TmpInf1"
#从文件配置行得到变量TmpInf1,TmpInf2,TmpInf3,TmpInf4
system_set_value $MyInf
#若文件配置行中的数值和缺省配置行的数值不同
if [ "$OldTmpInf1" != "$TmpInf1" ]; then
echo "Warning! Your value is$TmpInf1, but default value is $OldTmpInf1."
sub_echo_read "Are you want toreplace it? (y/n):\c"
if [ "$SurCho" = "n" ]; then
sub_echo_log "Warning!$MyInf was not default value."
else
#使用缺省配置行替换配置文件中的配置行,并写回到配置文件中
cat $TmpFile | sed"s/$MyInf/$SetInf/" > $TmpFile1
cp $TmpFile1 $TmpFile
sub_echo_log "OK! $TmpInf1was replaced with $OldTmpInf1"
fi
fi
else #若配置文件中不存在相应的配置行
sub_echo_log "Error! not$SetInf"
#将缺省配置行添加到配置文件中
echo "$SetInf" >> $TmpFile
sub_echo_log "OK! Add $SetInf"
fi
23.iTELLIN示例七:取得字符串的长度 ##############################################
# name : get_length
# description: get the length of string
# input: string
# return: lenght of string
##############################################
get_length()
{
return `echo $1 | awk '{printlength($0)}'`
}
取得字符串$0的长度,用以判断其最后一个字符是否是字符/,如果是,则删除此字符
get_length $FileDir
StrLength=$?
if [ "/" = "`echo $FileDir |cut –c $StrLength`" ]; then
((StrLength=StrLength-1)) #此行sh不支持,应改用expr
FileDir="`echo $FileDir | cut-c1-$StrLength`"
fi
24.用另外的文件作为函数库
主程序在autoinstall文件中执行,有一个解压缩的功能由另一个文件file_uncmp实现,则在autoinstall文件中调用如下:
#调用file_uncmp文件中的函数解压缩
$IN_PATH/file_uncmp $CmpdFile $IN_PATH/mend_check_dir
在file_uncmp文件中:
#!/bin/ksh
file_uncmp()
{
......
}
if [ $# -ne 2 ]; then
echo "Error usage!"
exit 1
fi
file_uncmp $1 $2
25.解压缩文件到一个目录
###########################################################
# 函数:file_uncmp
# 目的:压缩文件解压
# 方法:
# 输入:压缩文件名,解压路径
# 输出:解压后的目录和文件
# 限制:
###########################################################
file_uncmp()
{
#$1为压缩文件的全路径
CmpdFile=$1
#$2为目录
UncmpPath=$2
#判断解压路径是否正确
CurDir="`pwd`"
if [ "$UncmpPath" != "$CurDir" ]; then
echo "Error uncompress path$UncmpPath!"
exit 1
fi
#判断解压文件是否存在
if [ ! -f $CmpdFile ]; then
echo "File $CmpdFile not find."
exit 1
fi
#删除解压缩目的目录中的所有文件。
rm -f $UncmpPath/*.tar.Z
rm -f $UncmpPath/*.tar
rm -f $UncmpPath/*.CPI
rm -f $UncmpPath/*.war
echo "\nCopy file, Please wait......"
#将压缩文件拷贝到目录目录中(判断操作是否成功)
cp $CmpdFile $UncmpPath
if [ "$?" -ne 0 ]; then
echo "Can not access file$CmpdFile"
exit 1
fi
SrcfType=false
echo "\nUncompress file. Please wait......"
#判断是否存在tar.Z文件
ls *.tar.Z > /dev/null 2>&1
if [ "$?" -eq 0 ]; then
SrcFile="`ls *.tar.Z`"
SrcfType=true
Opts="`uncompress -f$SrcFile`"
Rtns=$?
if [ $Rtns -ne 0 ]; then
echo "$Opts"
echo "Uncompress file $SrcFilefailed!"
exit 1
fi
fi
#判断是否存在tar文件
ls *.TAR > /dev/null 2>&1
if [ "$?" -eq 0 ]; then
SrcFile="`ls *.TAR`"
SrcfType=true
Opts="`tar xvf $SrcFile`"
Rtns=$?
if [ $Rtns -ne 0 ]; then
echo "$Opts"
echo "TAR file $SrcFile failed!"
exit 1
fi
rm -f $UncmpPath/*.TAR
exit 0
fi
ls *.tar > /dev/null 2>&1
if [ "$?" -eq 0 ]; then
SrcFile="`ls *.tar`"
SrcfType=true
Opts="`tar xvf $SrcFile`"
Rtns=$?
if [ $Rtns -ne 0 ]; then
echo "$Opts"
echo "Tar file $SrcFilefailed!"
exit 1
fi
fi
ls *.war > /dev/null 2>&1
if [ "$?" -eq 0 ]; then
SrcFile="`ls *.war`"
SrcfType=true
Opts="`jar xvf $SrcFile`"
Rtns=$?
if [ $Rtns -ne 0 ]; then
echo "$Opts"
echo "Tar file $SrcFilefailed!"
exit 1
fi
fi
ls *.CPI > /dev/null 2>&1
if [ "$?" -eq 0 ]; then
SrcFile="`ls *.CPI`"
SrcfType="TRUE"
Opts="`cpio -icvumd <$SrcFile`"
Rtns=$?
if [ $Rtns -ne 0 ]; then
echo "$Opts"
sub_echo_log "Cpio SCP sourcefile $SrcFile failed!"
exit 1
fi
fi
if [ "$SrcfType" = false ]; then
echo "Format of source file$CmpdFile is not known!"
exit 1
fi
echo ""
echo "Uncompress file completed."
rm -f $UncmpPath/*.tar.Z
rm -f $UncmpPath/*.tar
rm -f $UncmpPath/*.CPI
}#end of file_uncmp()
26.判断操作是否成功
拷贝:
cp $CmpdFile $UncmpPath
if [ "$?" -ne 0 ]; then
echo "Can not access file$CmpdFile"
exit 1
fi
取得主机名和IP地址:
#获取主机名
HostName=`hostname`
#过滤纯注释行(以#开头或者以空格+#开头的行),
#然后过滤127.0.0.1,获取本机的ip地址
HostIP=`cat /etc/hosts|grep -v "^[ ]*\#"|grep -v 127.0.0.1|grep$HostName|awk '{print $1}'`
if [$? -ne 0 ];then
sub_echo_log "Error! can't get HostIP"
exit 1
fi
检测系统:
echo "Your SunOs version is`uname -r`"
if [ "$?" !="0" ]; then
sub_echo_log "Error! Checksolaris version failure!"
return
fi
一些要判断操作结果是否成功的命令:
cp、cat、df、ls、pkginfo、ifconfig、ping、
uname、mkdir、pkgadd、su、cd、netstat、groupadd、groupdel
27.创建一个组
以下函数创建一个组,调用:group_creat "informix" "101
###############################################################
# 函数:group_creat
# 目的:创建组
# 方法:
# 输入:组名、组ID
# 输出:组
# 限制:
###############################################################
group_create()
{
#如果存在此组或者存在和组ID相同的组,均删除,然后重新创建一个组
if [ ! -f "/etc/group" ]; then
echo "File /etc/group does notexist!"
exit 1
fi
#$1为组名,$2为组ID
GroupName=$1
GroupID=$2
GroupFlag=false
while read LineContent
do
OldGroupName="`echo"$LineContent" | awk -F: '{print $1}'`"
if [ "$GroupName" ="$OldGroupName" ]; then
GroupFlag=true
break
fi
done < "/etc/group"
if [ "$GroupFlag" = true ]; then
groupdel $OldGroupName
sub_echo_log "Del group$OldGroupName existed."
fi
GroupFlag=false
while read LineContent
do
OldGroupID="`echo"$LineContent" | awk -F: '{print $3}'`"
if [ "$GroupID" ="$OldGroupID" ]; then
OldGroupName="`echo"$LineContent" | awk -F: '{print $1}'`"
GroupFlag=true
break
fi
done < "/etc/group"
if [ "$GroupFlag" = true ]; then
exec_Cmd "groupdel$OldGroupName"
sub_echo_log "Del group$OldGroupName existed for the same group ID."
fi
exec_Cmd "groupadd -g $GroupID$GroupName"
sub_echo_log "OK! Creat group$GroupName."
}#end ofgroup_creat()
28.创建一个用户
##################################################################
#函数:user_creat
# 目的:自动创建用户
# 方法:
# 输入:用户名,用户ID,组名,主目录
# 输出:用户
# 限制:
#################################################################
user_creat()
{
if [ ! -f "/etc/passwd" ]; then
echo "File /etc/passwd does notexist!"
exit 1
fi
UserName=$1
UserID=$2
GroupName=$3
HomePath=$4
UserFlag=false
while read LineContent
do
OldUserName="`echo"$LineContent" | awk -F: '{print $1}'`"
if [ "$UserName" ="$OldUserName" ]; then
UserFlag=true
break
fi
done < "/etc/passwd"
if [ "$UserFlag" = true ]; then
echo "Delete old files,wait......"
#删除主目录中的所有文件
rm -r $HomePath/* >> /dev/null2>&1
#删除用户
userdel $OldUserName
sub_echo_log "Del user$OldUserName existed."
fi
UserFlag=false
while read LineContent
do
OldUserID="`echo"$LineContent" | awk -F: '{print $3}'`"
if [ "$UserID" ="$OldUserID" ]; then
OldUserName="`echo"$LineContent" | awk -F: '{print $1}'`"
UserFlag=true
break
fi
done < "/etc/passwd"
if [ "$UserFlag" = true ]; then
#删除主目录中的所有文件
su - $OldUserName -c "rm -r *; rm-r .*" >> /dev/null 2>&1
#删除用户
userdel $OldUserName
sub_echo_log "Del user$OldUserName existed for the same user ID."
fi
useradd -u $UserID -d $HomePath -g$GroupName -s /bin/csh -m -k /etc/skel $UserName
chgrp $GroupName $HomePath
chown $UserName $HomePath
#如果是sms用户则建到scp用户的链接
if [ "$UserName" ="sms" ]; then
rm $SMS_HOME/v20 > /dev/null2>&1
su - sms -c "ln -s $SCP_HOME/smsv20"
if [ "$?" != "0" ];then
sub_echo_log "Error! Creatsign link v20 failure."
fi
fi
sub_echo_log "OK! Creat user$UserName."
echo "Please input user $UserNamepassword."
passwd $UserName
}
29.判断一个字符串是否是正整数
##############################################
# name : is_positive_integer
# description: judge whether the string is apositive integer
# input: string
# output: 0--is positive integer
# others--not a positive integer
##############################################
is_positive_integer()
{
Str=$1
# trim the left and right space
Str=`echo $Str`
# is null string ?
if [ "-${Str}" = "-" ]; then
#echo "null str"
return 1
fi
# is equal zero
if [ "-${Str}" = "-0" ]; then
#echo "equal zero"
return 1
else
# try to remove number characters fromthe string
nRes=`echo ${Str} | sed 's/[0-9]*//g'`
# get the length of the remained string
nLen="`echo ${nRes} | awk '{printlength($0)}'`"
# if has characters remained
if [ nLen -ne 0 ]; then
#echo "containothers characters or less than zero"
return 1
else
#echo "is positiveinteger"
return 0
fi
fi
}
30.判断当前用户是否有root权限
#检查是否为root用户
Opts=`id | grep '(root)' | grep -c 'uid=0'`
if [ ${Opts} -eq 0 ]; then
echo "Error! autoinstall must run with root user."
exit 1
fi
31.判断一个字符串是否是整数
##############################################
# name : is_integer
# description: judge whether the string is ainteger
# input: string
# output: 0--is integer
# others--not a positive integer
##############################################
is_integer()
{
Str=$1
# trim the left and right space
Str=`echo $Str`
if [ "-$Str" = "-" ];then
#echo"null str"
return 1
fi
# try to remove number characters from thestring
nRes=`echo ${no} | sed's/^\([+-]*\)[0-9][0-9]*//g'`
# get the length of the remained string
nlen="`echo ${nRes} | awk '{printlength($0)}'`"
# if has characters remained
if [ "-$nlen" != "-0" ];then
#echo "contain others characters or less than zero"
return 1
else
#echo"is a integer"
return 0
fi
}
32.删除某个文件夹下若干天以来未改动的文件
##############################################
# name : rm_file_ago
# description: rm files days ago
# input: directory
# ndays : days ago
# return: N/A
##############################################
rm_file_days_ago()
{
list=`find $1 -mtime +$2 -print`
for file in $list
do
echo "rm $file"
rm-fr $file
done
}