shell编程
1. 什么是shell?
用户登录Linux后,就会出现一个系统提示符号,可以在符号后输入一大堆命令,并获得预期效果,到底幕后是谁在帮我们处理这一大堆事情呢?就是Shell,当用户登录时,实际上是进入到一个叫Shell的程序中。
Shell担任了翻译的角色,将用户输入的每个命令翻译成Linux系统能够识别的指令。
交互模式
当Shell收到用户输入命令后,就开始执行这项命令,并把结果显示到屏幕上,结束后Shell又会显示系统提示符,等待用户输入下一条命令。
后台运行
后台运行的符号为”&”,在命令后面加上“&”符号,就可以将程序放到后台运行。
在后台执行的程序怎么使它恢复到前台来运行呢?执行fg命令。
程序已经在前台运行,执行ctrl + z就可以放入后台。
如果有多个进程在后台运行,执行jobs命令,能够列出所有在后台执行的进程,那个中括号([ ])里面的数字就是 jobs 的代号 ,通过fg %number 就可以恢复指定的后台进程。
[lishuhuakai@localhost 01]$ top& ##在后台运行top命令 [1] 2317 [lishuhuakai@localhost 01]$ jobs ##查看正在后台运行的程序 [1]+ Stopped top [lishuhuakai@localhost 01]$ fg 1 ##fg + 编号,将编号代表的程序从后台调到前台 Top... |
ctrl + c是终止程序的运行。
输入输出重定向
通过重定向符”>””<”将标准输入输出重新定向。
很简单的一个小例子,fifo1(文件哦)是一个管道,cat命令用于输出管道里的内容,cat < fifo1表示,fifo1管道里的数据用cat输出来。
[root@localhost gaozhen]# ls -l > file1
[root@localhost gaozhen]# cat < file1
然后在相同目录下再开一个窗口操作:
将ls –l的结果输出到fifo1中。
结果很有趣,原来的那个窗口输出了结果。
我们也可以这么玩,ls –l > a.txt即将结果输出到a.txt文件中,如果当前目录下没有该文件,会新建一个文件,是不是很方便?
管道
通过管道符号“|”完成一系列命令的顺序处理。
[root@localhost gaozhen]# ps -u root
[root@localhost gaozhen]# ps -u root | grep bash
4007 pts/1 00:00:01 bash
4224 pts/2 00:00:00 bash
如上图的一个例子,
|主要的作用是,将上一个命令的结果作为下一个命令数据的来源,
如运行ps –ulishuhuakai会输出一堆数据,而grep bash就是从数据中查找bash字符,并输出来,两个一组合,就有了上面的结果。
通配符
通配符的作用是在处理文件的时候用通配符模糊匹配一个或多个字符。
使用通配符会使得某些操作变得十分简单,如进入RHEL_6.3 i386 Disc 1,直接用cdRH*即可。
类似的,包含ma字符的文件名或目录名,我们可以这么表示*ma*。
[root@localhost /]# cd gao*
[root@localhost gaozhen]#
环境变量
Shell是个庞大的程序,为了使工作环境符合用户的习惯或者应用的需要,可以让用户自行设置Shell使用环境。
Shell Script
Shell最重要也是最负责的就是Shell Script。Shell除了解释命令以外还有重要的功能就是程序语言,可以通过Shell Script进程程序设计,完成更加复杂的功能。
2. shell编程
shell变量
既然Shell能够编程,当然就一定具备变量定义的功能。
变量分为预定义变量和环境变量
预定义变量---通常是用户自行定义的特殊用途变量,有效返回限于定义变量的Script中。
环境变量---通常用来定义系统重要的设置,主要功能为提供程序执行时的参考
定义预定义变量的方法
语法:varName=value
在Shell中定义变量很简单,不需要定义变量类型,只需要用“=”给变量赋值即可。
变量名称与等号之间不能有空格,否则Shell会认为是错误的命令。
[root@localhost gaozhen]# varname= value
bash: value: command not found
[root@localhost gaozhen]# varname=value
使用变量的值,只需要在变量前加“$”。
[root@localhost gaozhen]# echo $varname
value
set---查看所有已经设置的变量。
[root@localhost gaozhen]# set | grep varn
varname=value
|这个命令的强大
unset varName---删除设置的变量。
设置环境变量使用export命令
语法:export varName=value
env---显示当前环境变量
export –n varName 删除设置的环境变量。
上面是.bash_profile里面的内容,在path变量中加入了当前目录(.),然后使用export命令设置了环境变量。
环境变量的作用域
在.bash_profile中定义的变量在用户登录后一直有效。
在普通脚本文件中定义的变量只在脚本内部有效。
几个常用的环境变量
变量名 | 说明 |
PWD | 显示当前路径 |
UID | 用户ID |
BASH_VERSION | Bash的版本 |
HOSTTYPE | 显示计算机平台 |
OSTYPE | 显示操作系统种类 |
PATH | 系统命令,文件查找路径 |
HOME | 用户的home目录 |
bash设置文件
/etc/profile
这是系统的Shell设置文件,用户可以将系统最重要的环境变量定义到这个文件中。
每次登陆的时候Bash都会读这个文件。
~/.bash_profile
是用户个人的Bash设置文件,用户登录的时候bash就会读取该用户目录下的.bash_file文件。
~/.bashrc
每次启动shell时候都会读取这个文件。
向下面是一个shell执行脚本:
第一句话 #! /bin/sh 是通知系统用/bin/sh程序来执行该脚本,不要问为什么,照这么写就可以了。
a=5,b=3定义了两个变量,echo是向屏幕输出的意思,$a,$b是引用变量a,b的值,一般echo后面接的语句,你添加了””,’’,或者什么都不加,都会被认为是字符。
下面
! /bin/sh
a=5
b=4
echo a=$a
echo b=$b
if (test "$a" = "$b") then
echo a=b
else
echo a!=b
fi是if语句,判断a和b的值(字符)是否相等,相等就输出a=b,否则就输出a!=b。执行结果如下:
以“#”开头的行代表注释。
字符串前面加”$”代表它是一个变量,
如果”$”后面是数字,代表第几个参数
$1代表第一个参数,$2代表第二个参数,$0代表命令本身
参数详细说明
参数 | 说明 |
$i | 代表第i个参数 |
$# | 代表参数个数 |
$* | 代表所有参数 |
$? | 上一个命令的返回值 |
一个简单的例子:
! /bin/sh
ls #ls讲文件目录下的文件或者文件目录显示出来,该命令的返回值是0,
echo $? 这个他妈的干啥的
echo $# #代表参数的个数
echo $1 #$1代表第一个参数
echo $* #$*是所有的参数。
下面是运行的结果:
[root@localhost gaozhen]# ./gao 1 2 3 4
sh-3.2# exit
exit
a.out datafile datfile demo direc file1 gao gaozhen1 man mydan sysrq.txt
0
4
1
1 2 3 4
首先执行ls命令,该命令的返回值是0,$#代表参数的个数,如图,我一共输入了4个参数,$1代表第一个参数,$*是所有的参数。
shift语句
$i只能提供0到9这10个数据参数,如果参数超过10个,怎么办呢?
shift能使引用数移位,如此就可以将引用过的引数移掉,把位置留给下一个引数。
echo $# $*
shift
echo $# $*
一个例子如下:
! /bin/sh
echo $# $*
shift
echo $# $*
shift
echo $# $*
我们看一下执行结果:
[root@localhost gaozhen]# ./gao 1 2 3 4 5 6 7 8 9 0 11
sh-3.2# exit
exit
11 1 2 3 4 5 6 7 8 9 0 11
10 2 3 4 5 6 7 8 9 0 11
9 3 4 5 6 7 8 9 0 11
很好理解第一次的时候参数个数是11,然后列出了所有的参数,执行shift之后,参数左移,挤掉了第一个参数,因此参数个数为10,接下来类似推理。
以“` `”符号包含的内容不是字符串,而是代表这是一个shell 命令。
echo “today is” `date`
前面是字符,后面`date`表示执行date这个命令。
PDATE=`date`
! /bin/sh
DATE=`date`
echo "today is" `date`
echo 'today' 'is' $DATE
代表定义一个变量PDATE,将date执行完成输出的结果放入变量PDATE中。
[root@localhost gaozhen]# ./gao
sh-3.2# exit
exit
today is Sat Apr 9 00:30:43 CST 2016
today is Sat Apr 9 00:30:43 CST 2016
运行结果如下:
这里注意一点单引号和双引号在shell里面基本没有区别。
expr命令
“expr”是用来取计算的结果。
a=9
b=10
var1=$a+$b
echo $var1
输出结果是”9+10”
[root@localhost gaozhen]# a=9
[root@localhost gaozhen]# b=10
[root@localhost gaozhen]# var1=$a+$b
[root@localhost gaozhen]# echo $var1
9+10
“expr”是用来取计算的结果。
var1=`expr $a + $b`
注意:“+”前后都需要有空格
[root@localhost gaozhen]# var1=`expr $a + $b`
[root@localhost gaozhen]# var1
bash: var1: command not found
[root@localhost gaozhen]# echo var1
var1
[root@localhost gaozhen]# echo $var1
19
[root@localhost gaozhen]# var1=`expr $a - $b`
[root@localhost gaozhen]# echo $var1
-1
[root@localhost gaozhen]# var1=`expr $a \* $b`
[root@localhost gaozhen]# echo $var1
90
shell中的运算
http://www.cnblogs.com/craftor/p/3811639.html
read命令
read命令用于从终端或文件读取输入。read命令读取一个输入行,直至遇到换行符。行尾的换行符在读入时将被转换成一个空字符。
如果read命令后有变量名,输入内容赋给该变量,如果read命令后未跟变量名,读入的行将被赋值给内置变量REPLY。
[root@localhost gaozhen]# ./gao
sh-3.2# exit
exit
12
a=12
13
b=13
12+13
25
运行结果是:
! /bin/sh
read a
echo a=$a
read b
echo b=$b
#a=5
#b=6
c=$a+$b
d=`expr $a + $b`
echo $c
echo $d
第一种if条件语句
if (test condition) then
commands
else
commands
fi
if条件语句中test是一个固定关键字,用来判断condition的描述是否正确,正确继续执行下面语句,错误执行else后面语句。
fi表示if语句结束。
! /bin/sh
if (test "$1" = "start") then
echo "is start"
else
echo "is nothing"
fi
[root@localhost gaozhen]# ./gao
sh-3.2# exit
exit
is nothing
运行结果是:
第二种if条件语句
if [ -option expr ]; then
commands
else
commands
fi
不同的条件代表不同的判断方式。
例如 if [ -r file ];,”[””]”里面都要加上空格,”]”后面要加”;”号。
-option说明
option | 说明 |
-d file | 文件存在并且是个目录 |
-e file | 文件存在 |
-r file | 文件存在并且可读 |
-w file | 文件存在并且可写 |
-x file | 文件存在并且可执行 |
if [ -f abc.c ]; then
echo "have abc.c"
else
echo "have not abc.c"
fi
[root@localhost gaozhen]# ./gao
sh-3.2# exit
exit
is nothing
[root@localhost gaozhen]# vi gao
[root@localhost gaozhen]# vi gao
[root@localhost gaozhen]# ./gao
sh-3.2# exit
exit
have not abc.c
[root@localhost gaozhen]# touch abc.c
[root@localhost gaozhen]# ./gao
sh-3.2# exit
exit
have abc.c
如果在当前目录下存在abc.c就会输出”have abc.c”,否则就会输出”have not abc.c”。
while循环语句
while [ expr ];
do
commands
done
expr为真的时候,while循环一直下去,直到expr为假。
运行结果为:
[root@localhost gaozhen]# ./gao
sh-3.2# exit
exit
0
1
2
3
[root@localhost gaozhen]# vi gao
! /bin/sh
times=0
while [ "$times" != "4" ];
do
echo $times
times=$[$times + 1]
done
case分支条件语句
case “string” in
pattern_1)
commands
;;
pattern_2)
commands
;;
*)
commands
;;
esac
当条件语句中的 string等于pattern字符串时执行pattern下面命令。
当没有符合条件时,最后执行*)。
[root@localhost gaozhen]# ./gao stop
sh-3.2# exit
exit
is stop
[root@localhost gaozhen]# cat gao
! /bin/sh
case "$1" in
start)
echo "is start"
;;
stop)
echo "is stop"
;;
*)
echo "is nothing"
esac
运行结果如下:
for循环语句
for varname in list ;
do
commands
done
list可以是一个字符串或数字
for每执行一次循环就将varname指定为list中的一个值,直到list这个数组结束。
运行结果如下:
[root@localhost gaozhen]# ./gao
sh-3.2# exit
exit
1
3
6
10
15
[root@localhost gaozhen]# cat gao
! /bin/sh
sum=0
for i in 1 2 3 4 5;
do
sum=$[$sum + i]
echo $sum
done
exit语句
exit code
exit可以让一个shell退出,与C语言的exit函数类似。
:语句
:
代表空语句,本身没有任何作用,但又是合法的语句,它经常用来填补程序设计的空缺。
自定义函数
shell和C语言一样,可以提供自定义函数。
function funcname
{
commands
}
使用函数前必须先定义函数。
运行结果如下:
带有参数的函数的例子:
运行结果如下:
带有参数和返回值的函数的例子:
运行结果如下:
[root@localhost gaozhen]# ./gao
sh-3.2#
sh-3.2# exit
exit
function is begin
[root@localhost gaozhen]# cat gao
! /bin/sh
function func
{
echo "function is begin"
}
func
[root@localhost gaozhen]# ./gao
sh-3.2# exit
exit
function is begin
7
[root@localhost gaozhen]# cat gao
! /bin/sh
function func
{
echo "function is begin"
a=$1
b=$2
echo `expr $a + $b`
}
func 3 4
[root@localhost gaozhen]# ./gao 2
sh-3.2# exit
exit
function is begin
7
[root@localhost gaozhen]# cat gao
! /bin/sh
function func
{
echo "function is begin"
a=$1
b=$2
echo `expr $a + $b`
}
func 3 4
带有参数和返回值的函数的例子:
sh-3.2# exit
exit
function is begin
4
[root@localhost gaozhen]# cat gao
! /bin/sh
function func
{
echo "function is begin"
a=$1
b=$2
return `expr $a + $b`
}
func 1 3
var1=$?
echo $var1
3. 一个例子
下面是一个非常经典的例子,主要用来运行守护程序,主要的功能有:
1. 只会运行一个进程实例;
2. 结束进程的时候可以全部结束该程序所有的进程实例;
3. 可以提供版本和状态的信息。
WHOAMI=`whoami` |
这句话会执行whoami命令,将用户名存进WHOAMI变量之中。
PID=`ps -u $WHOAMI | grep daemond | awk '{print $1}'` |
这句话比较复杂,首先执行ps –u 用户名,会将改用户运行的所有的进程列举出来,然后是|管道命令,即将ps命令的结果作为grep命令的来源,在结果中查找daemond这个字符串(即程序的名称),它也会返回查找的结果,然后再将结果作为awk命令的来源,awk '{print $1}'这句话是输出第一个参数,也就是daemond函数的PID。
if ( test "$1" = "" ) then echo "mydaemon [start] [stop] [version] [status]" exit 0 fi |
这句话的意思是,如果没有输入附加参数的话,那么提示mydaemon [start] [stop] [version] [status],即告诉用户该批命令的用法。然后退出。
if ( test "$1" = "status" ) then if ( test "$PID" = "" ) then echo "not run" else echo "run" fi exit 0 fi |
这句的意思是如果用户输入了status参数,请求查看程序运行的状况,如果PID变量为空,说明没有程序的示例在运行,就输出not run,否则输出run。
if (test "$1" = "start") then if ( test "$PID" = "" ) then daemond fi exit 0 fi |
如果输入了start参数,并且PID变量为空(说明还没有程序示例运行),就运行程序。如果不为空,就不会运行该程序实例,也就是说只能运行一个实例。
if ( test "$1" = "stop") then if ( test "$PID" != "") then kill $PID fi exit 0 fi |
如果参数为stop,即停止该程序,就杀掉PID变量里面的值所代表的进程。
if ( test "$1" = "version" ) then echo "version is 1.1.1" exit 0 fi |
status参数主要用来输出程序的版本信息。
! /bin/sh
WHOAMI=`whoami`
PID=`ps -u $WHOAMI` | grep daemond | awk '{print $`}'
if ( test "$1" = "") then
echo "mydaenon [start] [stop] [version] [status]"
exit 0
fi
if ( test "$1" = "status" ) then
if ( test "$PID" = "" ) then
echo "not tun"
else
echo "run"
fi
exit 0
fi
if( test "$1" = "start" ) then
if ( test "$PID" = "" ) then
daemond
fi
exit 0