您的位置:首页 > 运维架构 > Shell

Linux shell高级编程(上)

2012-01-11 16:10 447 查看
1. 概述在前面的章节中,我们讲解了shell脚本的基本编程,包括结构化命令,读取用户输入和测试命令。而这篇文章主要是描述shell脚本的高级编程部分,包括创建函数,流式编辑器sed和gawk的基本用法。 2. 函数部分 (1)基本格式:function name() { commands } 示例:!/bin/bash
#using a function in a script
#格式:function name(){ command}
function func(){
echo "this is an example of a function"

}
count=1
while [ $count -le 5 ]
do
func
count=$[ $count+1]
done
echo "this is the end of the loop" (2)使用变量接收函数输出当使用变量接收函数输出,必须用反引号,而且在函数中要用echo语句生成消息。result=`functionname`function functionname() { echo "message"} #!/bin/bash
#using the echo to return a value
function db1() {
read -p "Enter a value:" value
echo $[ $value*2 ] #使用echo生成消息,然后用变量接收函数值
}
result=`db1`
echo "the new value is $result (3)向函数传递参数环境变量使用标准的参数环境变量表示命令行给函数传递的参数,$0表示函数名,$1表示函数命令行的第一个参数,$2表示函数命令行的第二个参数。由于函数调用是在脚本内部的,所以只能在脚本内部向函数传递参数。在脚本外部,如在命令行中,那么传递的$1,$2是脚本参数变量,是向脚本传递的参数,此时,在函数内部是不能直接用的,因为函数有自己的特有的参数环境变量。必须手动的通过调用函数时传递到函数内部才可以使用。脚本的参数环境变量虽然与函数的参数环境变量形式相同,但有着本质的区别。脚本的参数环境变量是脚本使用的,而在函数内部时,函数的参数环境变量是函数特有的。一个相当于全局变量,一个相当于局部变量,如果在函数中使用与脚本中相同的参数环境变量$1,那么函数中的$1当然会覆盖脚本中的$1,如果不向函数中手动传值的话,这个变量就没有值了。所以,必须向函数中传递$1,而不能直接用脚本中的$1. 直接使用脚本中的参数环境变量:#!/bin/bash
#trying to access script parameters inside a function
#函数使用的变量$1和$2,不同于主脚本的$1和变量$2,如果想在函数>中使用这些值,那么必须在调用该函数时手动传入这些值
function func7(){
echo $[ $1*$2 ]

}
if [ $# -eq 2 ]
then
func7
echo "the result is $value"
else
echo "Usage:badtest a b"
fi 结果: [root@localhost chapter14]# ./test7 1 3
./test7: line 5: * : syntax error: operand expected (error token is "* ") 手动传递脚本中的参数环境变量#!/bin/bash
#trying to access script parameters inside a function
#函数使用的变量$1和$2,不同于主脚本的$1和变量$2,如果想在函数>中使用这些值,那么必须在调用该函数时手动传入这些值
function func7(){
echo $[ $1*$2 ]

}
if [ $# -eq 2 ]
then
value=`func7 $1 $2`
echo "the result is $value"
else
echo "Usage:badtest a b"
fi分析: fun7 $1 $2 把脚本中的参数环境变量手动传递到函数中去了。 (4)函数中的局部变量与全局变量全局变量指的是在shell脚本内处处有效的变量。如果在脚本的主代码中定义了全局变量,那么在函数内部就可以获得这个变量。而局部变量的定义可以用 local temp#!/bin/bash
#demonstrating the local keyword
#全局变量就是在shell脚本内处处有效的如果脚本的主代码中定义了>全局变量,那么函数内部可以获得这个值,同样要在函数内部定义了>全局变量,那么脚本的主代码也可以获得这个值。而局部变量只在函>数的内部有效 local是用来定义局部变量
function fun(){
local temp=$[ $value+5 ]
result=$[ $temp*2 ]

}

temp=4;
value=6;
fun
echo "the result is $result"
if [ $temp -gt $value ]
then
echo "temp is larger"
else
echo "temp is smaller"
fi (5)向函数传递数组向函数传递数组,必须将数组变量拆分为单个元素,然后使用这此元素值作为函数参数。函数内部可以将这些参数重组为新的数组变量。 传递数组示例1:#!/bin/bash
#array variable to function set
#向函数传递数组,首先将数组用$@取出来,然后在函数内部重新构建
数组,$@用来获得所有的命令行参数
function test(){
local newarray
newarray=(`echo "$@"`) //$@代表传递过来的所有参数,然后重新构造数组
echo "the new array value is:${newarray[*]}"

}
myarray=(1,2,3,4,5)
echo "the original array is ${myarray[*]}"
test ${myarray[*]} //传递数组元素结果:[root@localhost chapter14]# ./test11
the original array is 1,2,3,4,5
the new array value is:1,2,3,4,5 传递数组示例2:#!/bin/bash
function add() {
local sum=0
local newarray
newarray=(`echo "$@"`)
for value in ${newarray[*]}
do
sum=$[ $sum+$value ]
done
echo $sum
}
myarray=(1 2 3 4 5)
echo "the original array is: ${myarray[*]}"
arg1=`echo ${myarray[*]}`
result=`add $arg1`
echo "the result is $result" 运行结果:[root@localhost chapter11]# ./test111
the original array is: 1 2 3 4 5
the result is 15 返回数组: #!/bin/bash
function add() {
local originarray
local newarray
local elements
local i
originarray=(`echo "$@"`)
newarray=(`echo "$@"`)
elements=$[ $#-1 ]
for((i=0;i<=$elements;i++)){
newarray[$i]=$[ ${originarray[$i]}*2 ]

}
echo ${newarray[*]}

}
myarray=(1 2 3 4 5)
echo "the original array is:${myarray[*]}"
arg1=`echo ${myarray[*]}`
result=(`add $arg1`)
echo "the new array is:${result[*]}" 运行结果:[root@localhost chapter11]# ./test112
the original array is:1 2 3 4 5
the new array is:2 4 6 8 10
(6)创建库可以用bash shell创建函数库文件,然后可以在不同的脚本中引用该库文件。 函数库文件:#!/bin/bash
#my script functions
#创建库文件在脚本内部用点操作符来运行库文件脚本,这样脚本可以
使用这些函数
function addem(){
echo $[ $1+$2 ]

}
function multem(){
echo $[ $1*$2 ]

}
function divem(){
if [ $2 -ne 0 ]
then
echo $[ $1/$2 ]
else
echo -1
fi

} 在脚本中调用库文件,用source命令,source命令在shell脚本内部运行库文件脚本。source有一个短小的别名,即点操作符。下面在脚本中调用该函数库: #!/bin/bash
#using functions defined in a library file
. ./myfuncs //点操作符运行库文件脚本
value1=10
value2=5
result1=`addem $value1 $value2`
result2=`multem $value1 $value2`
result3=`divem $value1 $value2`
echo "the result of adding them is:$result1"
echo "the result of multiplying them is $result2"
echo "the result of dividing them is:$result3"结果:[root@localhost chapter14]# ./test14
the result of adding them is:15
the result of multiplying them is 50
the result of dividing them is:2 将库文件放到.bashrc,在root用户中就放到/root/.bashrc中去。由于每次无论bash shell是交互式启动还是从已有的shell启动新的shell,都会在主目录下查找这个文件。这样就可以在新的shell中直接使用这个库函数。 在 /root/.bashrc 中加入: . /home/shell/myfuncs 然后在命令行中运行: source /root/.bashrc[root@localhost chapter14]# addem 1 2
3
即看到,可以在shell命令行中任意调用函数库中的函数了。 3. sed基础知识sed也称为流编辑器,它每次读取一行数据,将该数据与所提供的编辑器命令进行匹配,根据命令修改数据流中的数据,然后将数据输出到stdout中去。在流编辑器将全部命令和一行数据匹配完之后,它将读取下一行数据,并重复上面这个过程。处理完数据流中的全部数据之后,流编辑器停止。 gawk比sed更先进的地方是提供了一种编程语言而不仅仅是编辑器命令行。 (1)在命令行中定义编辑器命令替换命令: s. s命令用第二个字符串去替换与文本匹配的两斜杠之间的第一个字符串。 例子:[root@localhost chapter14]# echo "this is a test"|sed 's/test/big test/'
this is a big test 分析: 管道的输出作为流编辑器sed的输入。 如果从sed命令执行多个命令,只需要用-e选项,并且两个命令之间用;隔开。 [root@localhost chapter14]# cat <data1
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog. [root@localhost chapter14]# sed -e 's/brown/green/; s/dog/cat/' data1
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat. (2)从文件读取编辑器命令-f从指定文件读取命令。script1: s/brown/green/
s/fox/cat/[root@localhost chapter14]# sed -f script1 data1
The quick green cat jumps over the lazy dog.
The quick green cat jumps over the lazy dog.
The quick green cat jumps over the lazy dog.
The quick green cat jumps over the lazy dog.
The quick green cat jumps over the lazy dog.
The quick green cat jumps over the lazy dog.
The quick green cat jumps over the lazy dog. (3)替换选项a.替换标记格式:s/pattern/replacement/flags
替换标记flags:数字: 表示新文本的替换模式g: 表示用新文本替换现有文本的全部实例p: 表示打印原始行的内容w file:将替换结果写入文件 示例: [root@localhost chapter14]# cat <data4
This is a test of the test script
This is the second test of the test script [root@localhost chapter14]# sed 's/test/trial/2' data4
This is a test of the trial script
This is the second test of the trial script即将第2个test替换成trial. [root@localhost chapter14]# sed 's/test/trial/g' data4
This is a trial of the trial script
This is the second trial of the trial script替换所有的test成trial. p命令是打印原始行的内容。-n选项是禁止编辑器的输出。那么p命令与-n选项使用就表示打印生成替换命令已经修改的那些行。 [root@localhost chapter14]# cat <data6
this is line1
this is line2
this is line3
this is line4 [root@localhost chapter14]# sed -n 's/line1/line/p' data6
this is line -n禁止编辑器输出p打印已经修改的行。所有 -n与p只打印已经替换的行。如果没有-n,将会打印已经修改的行和编辑器的输出。 [root@localhost chapter14]# sed 's/line1/line/p' data6
this is line
this is line
this is line2
this is line3
this is line4 b.替换字符:正斜杠的替换。 sed 's///bin//bash///bin//csh/' /etc/passwd 必须使用反斜杠对正斜杠进行转义。由于替换标记中有正斜杠。也可以使用一个不同的字符串定界符。如!sed 's!/bin/bash!/bin/csh!' /etc/passwd c.使用地址如只替换第二行。sed '2s/dog/cat/' data12表示只替换第二行。 sed '2,3s/dog/cat/' data1
2,3表示起始行与结束行。替换第2行与第3行。 sed '2,$s/dog/cat/' data1替换第2行到结束行。 2,$ d. 使用文本模式筛选器/pattern/command sed -n '/root/s/bash/csh/p' /etc/passwd 表示匹配/root/的替换。 e. 组合命令如果在单独一行上执行多个命令,用大括号将命令括在一起。 [root@localhost chapter14]# sed '2{
> s/fox/elep/
> s/dog/cat/
> }' data1 表示在2行上执行如下两个命令。 (4)删除行删除命令用d来完成。sed '3d' data6表示删除第3行。sed '2,3d' data6表示删除第2行与第3行。 (5)插入与附加文本 插入命令(i):在指定行之前添加一个新行附加命令(a):在指定行之后添加一个新行 格式:sed '[address]command/ new line' [root@localhost chapter14]# echo "testing"|sed 'i/this is a test'
this is a test
testing [root@localhost chapter14]# sed '3i/this is a test' data6
this is line1
this is line2
this is a test
this is line3
this is line4 [root@localhost chapter14]# sed '3a/this is a test' data6
this is line1
this is line2
this is line3
this is a test
this is line4 (6)更改行 c命令[root@localhost chapter14]# sed '3c/this is a test' data6
this is line1
this is line2
this is a test
this is line4更改第3行。 [root@localhost chapter14]# sed '/line3/c/this is a test' data6
this is line1
this is line2
this is a test
this is line4查找到line3的行更改。 (7)打印命令p用于打印文本行。=用于打印行号 [root@localhost chapter14]# echo "this is a test"|sed 'p'
this is a test
this is a test
[root@localhost chapter14]# echo "this is a test"|sed -n 'p'
this is a test 第一个例子的第一行是sed输出,第二行是p输出的。 [root@localhost chapter14]# sed '=' data6
1
this is line1
2
this is line2
3
this is line3
4
this is line4 打印行号。sed ''(8)读写文件[address] w filename [root@localhost chapter14]# sed -n '1,2w test' data6[root@localhost chapter14]# cat <test
this is line1
this is line2将第1行与第2行写入到test. [address] r filename [root@localhost chapter14]# sed '$r data11' data6
this is line1
this is line2
this is line3
this is line4
this is an added line.
this is the second added line.从data11中读出两行加入到data6的最后一行。 4. gawk基础知识gawk程序的基本格式:gawk options program file-F fs 字段文件分隔符-f file 指定读取程序的文件名-v var=value 定义gawk程序中使用的变量和默认值-mf N 数据文件中要处理的字段的最大数目-mr N 指定数据文件中的最大记录大小-W keyword 指定gawk兼容模式或警告级别 gawk的威力在于读取一行数据,处理这些数据可以生成任意类型的报告。 (1)从命令行读取程序脚本gawk程序脚本必须由{}来定义。而且脚本必须在单引号之内。 [root@localhost chapter14]# gawk '{print "hello"}'
hello
hello
world
hello 输入值时,始终打印出hello. (2)从文件中读取程序脚本自动变量: $0,$1,$2,....$0表示整个文本行$1表示文本行的第一个数据字段$2表示文本行的第二个数据字段各数据字段依据字段分割符进行分割。gawk默认的分割符是空白字符如空格符或者是制表符。 如:gawk -F: '{print $1}' /etc/passwd -F: 指定字段分割符为冒号。 script3: {test="'s userid is"
print $5 test $1
} gawk -F: -f script3 /etc/passwd -f指定读取的程序名。 (3)BEGIN与ENDBEGIN表示在处理数据之前运行的脚本。END在读取数据之后运行的脚本。 BEGIN {
print "the latest list of users and shells"
print " USERid Shell"
PRINT "-------- ------"
FS=":"

}

{
print $1 " " $7

}

END {

print "This concludes the listing"

} 运行结果:awk -f script4 /etc/passwd
the latest list of users and shells
USERid Shell
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
sync /bin/sync
shutdown /sbin/shutdown
halt /sbin/halt
mail /sbin/nologin
news
uucp /sbin/nologin
operator /sbin/nologin
games /sbin/nologin
gopher /sbin/nologin
ftp /sbin/nologin
nobody /sbin/nologin
nscd /sbin/nologin
vcsa /sbin/nologin
rpc /sbin/nologin
mailnull /sbin/nologin
smmsp /sbin/nologin
pcap /sbin/nologin
ntp /sbin/nologin
dbus /sbin/nologin
avahi /sbin/nologin
sshd /sbin/nologin
rpcuser /sbin/nologin
nfsnobody /sbin/nologin
haldaemon /sbin/nologin
avahi-autoipd /sbin/nologin
distcache /sbin/nologin
apache /sbin/nologin
postgres /bin/bash
oprofile /sbin/nologin
webalizer /sbin/nologin
dovecot /sbin/nologin
squid /sbin/nologin
mysql /bin/bash
xfs /sbin/nologin
named /sbin/nologin 关于awk就简单介绍到这了。 总结:主要介绍了shell高级编程中的函数部分,sed,与awk的简单用法。要分清函数中的参数环境变量与脚本中的参数环境变量。还有awk中的自动变量,虽然写法都是一样,但是表示的意义完全不相同。关于sed,awk的高级用法下一篇文章中继续介绍。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: