首页 > 代码库 > shell脚本编程

shell脚本编程

shell脚本编程

1.基本概念

  • shell中以#作为注释,使用方法和c中的//完全相同
  • shell中可以通过;在同一行执行两句命令,如ls ; pwd
  • 脚本程序是顺序执行的,一句一句逐行解释执行

2.变量的使用

变量主要分为全局环境变量和私有变量(即局部环境变量),有关环境变量,详见 Linux环境变量详解

  • 一个shell程序将继承其父shell的所有全局环境变量(即export的变量),并且可以对其重写而不影响父shell
  • shell中的变量是无类型的。shell不支持浮点型只支持整型和字符串型,判断标准:变量中只包含数字的话是整型,包含了其他是字符就是字符串型
  • 在shell脚本中可以随时定义变量,尤其要注意bash的语法中“=”两边不能有空格,变量值中间也不能有空格,有的话要用单引号围起来
test=123    #局部环境变量一般用小写
export TEST=123 #全局环境变量一般用大写
export MYNAME=‘XIAO BA WU‘ #变量值有空格,要用单引号围起来

export test #也可以这样把前面的局部变量导出到全局
  • 此外,和c语言一样,变量必须先定义再使用。若使用了一个未定义的变量,倒是不会报错,相当于调用了一个值为空的变量

  • shell中,不能直接由变量名获取变量值,根本原因是shell中的字符串可以不加引号,所以系统无法判断它是字符串还是变量名,故通过$来引用变量名获取其值。而当变量名作为右值时,系统可以直接判定其为变量,无需添加$

value1=value2   //value1的值为字符串"value2"
value1=$value2 //value1的值为value2的值
  • 此外$对变量名的判断是空格敏感的,当发生如下情况时,为了让bash能正确识别变量名,必须要使用{}将变量名包围,这是一个好习惯
name=123
name1=456

echo hah! hah! $name1 #打印name1的值
echo hah! hah! $name11 #打印name11的值(空值)
echo hah! hah! ${name}11 #打印name的值 
  • 当我们需要在一个字符串变量尾部,再续上几个字符时,可以:
name=‘aa bb cc d‘
name=$name‘d ee‘
  • $在shell中是关键字,如果要在字符串中单纯显示$符号,必须加\

  • shell中,我们可以使用反引号` (就是键盘上~所处的键),来将命令的返回值赋给变量,如:

PATH=`pwd`

3.输入与输出

  • echo可以直接打印字符串,一般情况不需要用单/双引号包围。但当字符串中出现单/双引号时,为了避免歧义,必须使用另外一种引号包围
echo abc123 #一般情况下直接打印
echo "let‘s go" #字符串里单引号,则用双引号包裹
echo ‘he says "shell is easy"‘ #字符串里双引号,则用单引号包裹
  • 默认的,echo在打印字符串的后面,会自动加上换行符。若想取消这个特性,可以加参数echo -n
  • 我们可以重定向输出,即将指令的返回值导出到指定的某个文件,方法是使用>(覆盖写) 或>>(追加写)
pwd > /home/root/path.txt       #把pwd指令的返回值覆盖写入文件
echo $i >> /home/root/log.txt   #把某个变量值追加写入文件
  • 同理,我们还可以重定向输入,即将文件中的内容导入至命令(作为命令的参数),方法是使用<<<。说实话输入重定向用的很少,主要是命令可以直接以文件名作为参数,何必重定向呢。。。。

4.脚本的进入与退出

进入脚本

退出脚本

当脚本最后一句命令执行完,就会自动退出

  • 在shell中的每个命令,在执行结束时都会返回给shell一个返回值,其值为0-255之间的整数值,一般0表示成功执行,正数表示发生了错误
  • 我们可以使用$?来获取上条执行命令的返回值
  • 脚本也可以由我们主动退出,在错误处理中经常使用,具体方法为exit var,var可以是我们指定的脚本退出时的返回值

5.数据操作

管道

管道的功能是:将一条命令的返回值,作为另一条命令的参数

  • 其实不用管道,用中间变量也能实现该功能,但是太臃肿,还是管道好。下面的语句先执行command1,得到结果作为参数执行command2,得到结果作为参数执行command3
command1 | command2 | command3

数学运算

由于shell中的变量有可能是字符串或整形,所以运算起来很蛋疼

  • 最原始的方法是使用expr命令,这种方法尤为蛋疼。用法如下,不仅要用到反引号来获取expr的输出,操作符前还要用到反斜杠,因为很多算数操作符在shell中是关键字(比如下面乘法操作符)
var1=1
var2=2
var=`expr $var1 \* $var2`
  • bash中后来又引入了一种新方法,如下,shell会自动将&[]包围的部分视为数学运算,并且不会误解算数操作符
var1=1
var2=2
var=$[$var1 * $var2]
  • 之前介绍的方法仅仅使用于整形运算,为了在shell中支持浮点运算,必须使用一个特殊的指令bc,即bash calculator。如下,通过管道将参数传给bc,用scale=4来指定结果要保留几位小数
var1=1
var2=3
var=`echo "scale=4; $var1 / $var2" | bc`

6.判断与循环结构

if语句

  • shell中的if语句结构如下,它通过判断command1的返回值,若0(即命令成功执行)则执行command2、command3;若1则不执行
if commandA
then
    command1
    command2
fi

#另一种风格的写法
if commandA; then
    command1
    command2
fi
  • 当然shell中也有else,还有elseif,用法分别如下:
if commandA
then
    command1
else
    command2
fi

if commandA
then
    command1
elif commanB
then
    command2
elif commandC
then
    command3
fi
  • 当需要多次判断时,也可用switch case来替代if else
case $USR in
root)
    echo root
    echo oh!;;
jack)
    echo jack;;
peter | ben)            #满足jack或ben
    echo hah! hah!;;
*)                      #星号代表默认情况
    echo error;;
esac

test语句

  • test命令是if语句的好伴侣,常用来判断条件是否满足,满足返回0,不满足返回1;test可以用来比较:数值、字符串、文件/路径。常见用法为:
if test condition
then
    commands
fi

#bash支持的另一种格式,本质也是调用了test,千万要注意在condition和方括号之间加空格
if [ condition ]
then
    commands
fi
  • 当test用于数值比较时,基本格式为var1 参数 var2,如下,具体参数有很多,可以上网查
if [ $var1 -eq $var2 ] #判断var1和var2变量值是否相等
if [ $var1 -gt 2 ] #判断var1的变量值是否大于2
  • 当test用于字符串比较时,基本格式也为var1 符号 var2,此外还可以使用[[ ]]来使用正则匹配
if [ $string1 = $string2 ] #判断变量string1和string2值是否相等
if [ $USR = !root ] #判断变量USR值是否不等于root
if [[ $USR == r* ]] #判断变量USR值是否以字母r开头
  • 当test用于判断文件和目录的状态时,基本格式为参数 filepath如下,具体参数有很多,可以上网查
if [ -d $MYPATH ] #判断位于$MYPATH的文件是否存在,并且是个目录
if [ -e $MYPATH ] #判断位于$MYPATH的文件是否存在
if [ -r $MYPATH ] #判断位于$MYPATH的文件是否可读
if [ -x $MYPATH ] #判断位于$MYPATH的文件是否可执行
  • test 还可以判断一个变量是否有值
if [ -z "$USR" ] #判断变量USR长度是否为零
if [ -n "$USR" ] #判断变量USR长度是否非零
  • 对于复合判断语句,shell中使用&&||来表示,尤其需要注意的是,shell中以命令返回0为真,1位假,故&&||操作以逻辑真假为准,不再以数值上的0和1为准
if [ condition1 ] && [ condition2 ]
if [ condition1 ] || [ condition2 ]
  • 此外&&还能用来作为简易版本的if语句,左边的命令返回真(即返回0),右边的命令才被执行
[ $? -ne 0 ] && mk_error "build rootfs Failed" && return 1

for语句

  • shell中for语句的基本用法是,每次循环,变量就套用列表中的元素值,循环至列表结束为止
#for语句假定列表元素之间以空格分割,若元素内部包含空格,则用双引号包围即可
for var in shanghai beijing "new york" guangzhou  
do
    commands
done

#for语句也可以将变量的内容作为列表值
list=‘shanghai beijing guangzhou‘
for var in $list  
do
    commands
done

#列表值的来源也可以是指令的输出,for将以空格来分割指令的输出,当输出结束时循环也结束
for var in `cat $file` #此处从一个文件中读取内容,以此作为列表值  
do
    commands
done
  • 现在来系统的讨论一下,for语句会将哪些字符作为列表元素的分割符?默认为空格、换行、制表符。我们可以通过变量IFS来指定分隔符,这是极为便利的一种机制
OLDIFS=$IFS    #先备份原本的IFS值
IFS=$‘\n:;‘    #指定分隔符为换行符、冒号、分号
#这里可以进行各种操作了
IFS=$OLDIFS    #还原IFS值
  • for语句还有一种强大的用法,即用通配符获取文件/目录
#这里将会遍历所有满足条件的目录,并将其作为列表值,每次循环赋给变量file 
for file in /home/root/.b* /home/root/test
do
    if [ -d $file ]
.....
<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

    shell脚本编程