在Shell中,我们在使用变量之前并不需要进行声明.相反我们可以在需要的时候进行简单的使用就可以了.在默认的情况下,所有的变量都是作为字符串进行
存储的,虽然有时我们会用数字为其赋值.Shell以及其他的一些实用的转换程序会将数字字符串转换成相应的值为进行操作.在Linux系统中是要区分大
小的,所以在S
在Shell中我们要访问变量的值,我们要在变量前加上一个$.当我们要为变量赋值时,我们可以只使用变量的名字,Shell会在需要的时候进行动态创建.检测变量内容一个简单的办法就是在终端进行输出,这时要在变量前加上一个$.
$ salutation=Hello
$ echo $salutation
Hello
$ salutation=”Yes Dear”
$ echo $salutation
Yes Dear
$ salutation=7+5
$ echo $salutation
7+5
$ read salutation
Wie geht’s?
$ echo $salutation
Wie geht’s?
在继续我们的学习之前我们要清楚引号的作用.
通常脚本中的参数是由空白字符来分隔的,如空格,Tab或是回车.如果我们要我们的参数包含一个或是更多个参数,我们就要使用引号了.
例如变量$foo的行为要看我们使用的引号的类型了.如果我们是用双引号,在这一行执行时就会用他的值进行替换,而如果我们使用单引号就不会发生这样的替换.我们还可以使用转义字符/来除去$的特殊意义.
在通常的情况下,我们双引号来包含字符串,这样就可以防止变量被空白符所分隔,而且会用变量的值进行替换.
在下面的这个例子中我们就会看到引号对于变量输出的影响:
#!/bin/bash
myvar=”Hi there”
echo $myvar
echo “$myvar”
echo ‘$myvar’
echo /$myvar
echo Enter some text
read myvar
echo ‘$myvar’ now equals $myvar
exit 0
Hi there
Hi there
$myvar
$myvar
Enter some text
Hello World
$myvar now equals Hello World
我们创建了变理myvar,并赋值为Hi
there.变量的内容由命令echo显示出来,从而可以看出$字符扩展对变量内容的影响.从这输出我们可以看出双引号并不会影响变量的替换,而单引号和
反斜线却会有这样的影响.我们同时使用一个read命令来从用户得到输入.
当启动一个Shell脚本时,一些变量会由环境中的值进行初始化.在脚本中这些变量通常为大写字母,从而与用户定义的变量进行区分,而用户定义的变理常用小写字母来表示.创建的变量依赖于我们个人的配置.其中的许多列在手册页中,但是基本的一些列在下面的表中:
如果我们的脚本调用一些参数,那么会建立一些其他的变量.即使没有传递参数,环境变量$#仍然存在,但是值却为0.
$1,$2,... 传递给脚本的参数.
$* 以单变量的形式显示所有的参数列表,由环境变量IFS中的第一个字符分隔.
$@ $*的一个灵巧变形.他并不使用IFS环境变量,所以如果IFS为空那么所有的所有的参数会一起运行.
$ IFS=’’
$ set foo bar bam
$ echo “$@”
foo bar bam
$ echo “$*”
foobarbam
$ unset IFS
$ echo “$*”
foo bar bam
正如我们所看到的,在双引号内,$@将参数进行分隔显示,而与IFS的值无关.通常来说,如果我们要访问参数,$@是一个很灵敏的选择.
我们不仅可以用echo命令打印出变量的内容,而且我们可以使用read命令来读取他们的内容.
下面的脚本展示了简单变量的处理.在我们输入了下面的脚本内容并保存为try_var,我们一定要记得用命令chmod +x try_var为其加上可执行权限.
#!/bin/sh
salutation=”Hello”
echo $salutation
echo “The program $0 is now running”
echo “The second parameter was $2”
echo “The first parameter was $1”
echo “The parameter list was $*”
echo “The user’s home directory is $HOME”
echo “Please enter a new greeting”
read salutation
echo $salutation
echo “The script is now complete”
exit 0
~$ ./try_var.sh foo bar baz
Hello
The program ./try_var.sh is now running
The second parameter was bar
The first parameter list was foo bar baz
The user's home directory is /home/mylxiaoyi
Please enter a new greeting
hello
The script is now complete
这个脚本创建了一个名为salutation的变量并显示他的内空,然后显示了各种参数变量,而环境变量$HOME已经存在并且已经有适当的值.
所有程序语言的基本原则是测试条件并在这些测试的基础上进行各种不同的操作.在我们讨论这个话题之前,我们先来看一下在Shell脚本中我们会用到的函数构造以及我们要使用的控制结构.
一个Shell脚本可以测试由命令行调用的任何命令的返回代码,包括我们自己书写的脚本.这就是我们在每一个Shell脚本最后包含exit代码的重要原因.
事实上,大多数的脚本大量的使用了Shell真假检测的test或是[命令.在大多数的系统上,[和test命令是同义的,但是当使用了一个[命令时而同
时为了可读在末尾使用了一个]命令.使用[命令看起来有一点奇怪,但是这个命令在代码中会使得命令的语法看起来要简单,整洁,并且与其他的程序语言很相
像.
ls -l /usr/bin/[
-rwxr-xr-x 1 root root 25040 2005-11-16 21:17 /usr/bin/[
我们会使用一个简单的测试例子来介绍test命令:检测一个文件是否存在.用于这个目的的命令是test -f <filename>,所以我们可以用下面的脚本:
if test -f fred.c
then
...
fi
我们也可以像下面的样子来写:
if [ -f fred.c ]
then
...
fi
test命令的返回代码(条件是否满足)决定于条件代码是否运行.
在这里我们要注意是我们必须在[和条件之间用空格进行分隔.我们可以用下面的方法来记住这一点:[是test命令的另一种写法,而我们要在test命令后输入空格.
如果我们喜欢将then与if放在同一行,我们必须要加一个冒号来与then进行分隔:
if [ -f fred.c ]; then
...
fi
我们可以用的test命令的条件类型有以下的三种:字符串比较,算术比较和文件条件.下面的三张表展示了这些条件类型:
string1 = string2 如果相等则为真
string1 != string2 如果不等则为真
-n string 如果不空则为真
-z string 如果为空则为真
expression1 -eq expression2 如果相等则为真
expression1 -ne expression2 如果不等则为真
expression1 -gt expression2 如果大于则为真
expression1 -ge expression2 大于等于则为真
expression1 -lt expression2 如果小于则为真
expression1 -le expression2 小于等于则为真
!expression 如查为假则为真
-d file 如果为目录则为真
-e file 如果存在则为真(在这里要注意的是,由于历史原因,-e选项并不可移植,所以常用的是-f选项
-f file 如果为常规文件则为真
-g file 如果设置了组ID则为真
-r file 如果文件可读则为真
-s file 如果文件大小不为零则为真
-u file 如果设置了用户ID则为真
-w file 如果文件可写则为真
-x file 如果文件可执行则为真
现在我们似乎走得有一点的太前了,但是接下来的是一个例子.在这里我们要测试文件/usr/bash,这样我们就可以清楚的看到这些条件的用法:
if [ -f /bin/bash ]
then
echo “file /bin/bash exists”
fi
if [ -d /bin/bash ]
then
echo “/bin/bash is a directory”
else
echo “/bin/bash is NOT a directory”
fi
在测试为真以前,所有的文件测试条件要法度文件存在.这个列表包含了test命令常用的选项,所以我们可查看手册页得到一个完全的信息.如果我们正在使用bash,而其中内嵌了test,我们可以用命令help test得到详细的信息.
*************************************************************************************************************
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*************************************************************************************************************
Shell编程--分述:
一、Shell变量 主要有本地变量和环境变量。
1、本地变量 -- 在用户现有运行的脚本中使用
1) 定义本地变量 格式: variable-name=value
例子:[root@jike1 /root]# LOCALTEST="test"
[root@jike1 /root]# echo $LOCALTEST (注意:echo $LOCALTEST 和 echo ${LOCALTEST}的效果是一样的)
(在变量名前加$, 可以取得此变量的值,使用echo命令可以显示变量的值)
2) 显示本地变量 格式: set
例子:[root@chinaitlab root]# set
3) 清除本地变量 格式:unset variable-name
例如:[root@jike1 /root]# unset LOCALTEST
此时再执行echo $LOCALTEST将看不到变量LOCALTEST的输出。
2、环境变量 -- 在所有的子进程中使用
1) 定义环境变量 格式: export variable-name=value (与本地变量的定义相比,多了一个export关键字)
例子:[root@chinaitlab /root]# export DOMAIN="chinaitlab.com"
[root@ chinaitlab shell]# vi testenv.sh
#!/bin/bash #表示用bash来解析脚本
#testenv.sh
echo $DOMAIN
[root@chinaitlab shell]# chmod +x testenv.sh
[root@chinaitlab shell]# ./testenv.sh
chinaitlab.com
2) 显示环境变量 格式: env (本地变量的显示使用set,环境变量的显示使用env)
例子: [root@chinaitlab test]# env
3) 清除环境变量 格式:unset variable-name (用法与本地变量相同,都使用unset)
例子: [root@chinaitlab shell]# unset DOMAIN
此时再执行./testenv.sh将看不到变量DOMAIN的输出。
3、其它变量
1) 位置变量 $0,$1,$2,$3……$9
2) 只读变量 readonly variable
注意:只读变量不能被清除和改变其值,所以要谨慎使用。
3) 特殊变量 $#,$?,$$(表示当前进程的PID)……
二、运算符和表达式
1、运算符是对计算机发的指令,运算符类型有:
算术运算符(+、-、*、/)
按位运算符(~、<<、>>、&、|、^)
逻辑运算符(&&、||、 > 、= = 、<、! =)
赋值运算符(=、+=、-=、*=、/=、%=、&=、^=、|=、<<=、>>=)
2、表达式是运算符和运算对象的组合体。
1) $[]:可以接受不同基数的数字的表达式
echo $[10+1] (输出:11)
echo "$[2+3],$HOME" (输出:5,/root)
echo $[2<<3],$[8>>1] (输出:16,4)
echo $[2>3],$[3>2] (输出:0,1 表达式为false时输出0,为true时输出1)
2) 字符表达式:直接书写,采用单引号,双引号引起来。
echo " $HOME,That is your root directory." (输出:/root,That is your root directory.)
echo ' $HOME,That is your root directory. ' (输出:$HOME,That is your root directory.)
单引号和双引号的区别在于:单引号是原样显示,双引号则显示出变量的值。
3) test表达式
三、控制结构
1、if语句
例: #!/bin/bash
#if.sh
if [ "10" -lt "12" ] #注意:if和[之间,[和"10"之间,"12"和]都有空格,如果不加空格,会出现语法错误
then
echo "Yes,10 is less than 12"
fi
2、case语句
例: #!/bin/bash
#case.sh
echo -n "Enter a start or stop:"
read ANS
case $ANS in
start)
echo "You select start"
;;
stop)
echo "You select stop"
;;
*)
echo "`basename $0`: You select is not between start and stop" >&2
#注意:>和&2之间没有空格,>&2 表示将显示输出到标准输出(一般是屏幕)上
exit;
;;
esac
3、for循环语句
格式: for 变量名 in 列表
do
命令1
命令2
... ...
done
4、until循环语句
格式: until 条件
do
命令1
命令2
... ...
done
5、while循环语句
格式: while 命令
do
命令1
break
命令2
continue
命令3
... ...
done
四、输入输出
1、几个重要的工具
1) echo
例:echo -n "Enter a number from 1 to 2:" (-n 表示不换行,此时光标停留在行尾)
2) read
例:read ANS (表示将用户的输入存放到变量ANS中)
3) cat (显示文件内容)
4) 管道( | ) (一个程序的输出作为另一个程序的输入)
例:ls -l | grep "d"
5) 文件重定向( >和>> )
例:ls -l > /tmp/a.txt (将输出的结果重写到a.txt这个文件中)
ls -l >> /tmp/a.txt (将输出的结果追加到a.txt这个文件中,常用于记录日志)
6) 标准输入( $0 )、标准输出( $1 )和标准错误( $2 )
采用文件描述符($0、$1、$2)来定义。
2、实例:readme.sh
#!/bin/bash
#readname.sh
echo -n "First Name: "
read firstname
echo -n "Last Name: "
read lastname subname
echo -e "Your First Name is :${firstname}/n " #加了-e表示将/n解析为转义字符
echo -e "Your Last Name is :${lastname}/n "
echo -e "Your Subname is :${subname}/n "
echo "Your First Name is :${firstname}/n " >>firstname.txt #这行没加-e,因此在输出中会原样显示/n
echo "Your Last Name is :${lastname}/n " >lastname.txt
echo "Your Subname is :${subname}/n " >&1
五、文本过滤
1、正则表达式 (就是模式匹配)
2、find (查找文件)
例:find ./ -name "*.txt" -print
3、grep (查找字符)
例:grep "[5-8][6-9][0-3]" access_log
4、awk (把一系列数据分域,即分成列)
例:awk '{print $1"/t"$4}' access_log
5、sed (对数据进行查找和替换)
例:sed -n 's/chinaitlab/hello/p' myfile.txt
(将myfile.txt文件中的chinaitlab替换成hello,并打印到屏幕上来,s表示替换,p表示打印。如果
加上重定向符就可以将替换后的内容输出到一个文件中去。)
6、sort (排序)
例:sort ip.txt
7、uniq (显示这一列是唯一的还是不唯一的,可以唯一化)
例:uniq ip.txt
8、split (可以对文件进行分割)
例:split myfile.txt
9、实例:kill_process.sh
#!/bin/bash
#kill_process.sh
current_PID=$$
ps -aux|grep "/usr/sbin/sshd"|grep -v "grep"|awk '{print $2}'>/tmp/${current_PID}.txt
for pid in `cat /tmp/${current_PID}.txt`
do
{
echo "kill -9 $pid"
kill -9 $pid
}
done
rm -f /tmp/${current_PID}.txt
六、Shell函数
1、定义函数有两种格式,分别为:
函数名()
{
命令1
... ...
}
function 函数名()
{
... ...
}
2、实例:func.sh
#!/bin/bash
#func.sh
# Source function library. # /etc/rc.d/init.d/functions中存放了大量已经写好的函数
. /etc/rc.d/init.d/functions # 引入/etc/rc.d/init.d/functions中的函数,相当于其它语言中的include
function hello ()
{
echo "Hello,$1 today is `date`"
}
echo "now going to the function hello"
hello chinaitlab
echo "back from the function"