shell程序设计

2018/08/30 Linux 共 5980 字,约 18 分钟

Shell程序的变量

shell中的变量和变量赋值

shell 变量定义由字母开始,可以包含数字,字母和下划线,例如 var1, username,pass_word等。

变量的赋值可以在程序运行中进行,也可以在变量定义时进行,例如UNIX=“SYSTEM V”,如果字符串中间没有空格和制表符,则可以不要双引号。

值得注意的是B-shell中等号=的两边是不允许有空格的。

shell中变量的访问和参数替换

在shell程序中,或者是shell命令中,使用操作符$来对shell变量进行访问。例如,要显示某个变量时,可以输入:

  $  echo  $UNIX  (系统将会显示SYSTEM V )

在某些场合下,为了明确表示对shell变量的引用,可以用花括弧{ }或者双引号将变量括起来,例如:

  $  echo  ${UNIX}
  $  echo  ${UNIX}Aaaaaa
  $  echo “$UNIX”  is very good

shell数组

array_name=(value0 value1 value2 value3)

shell中引号的说明:

单引号‘’、 双引号“”、 反引号`

(a)单引号’ :使用单引号时,shell将一对单引号之间的内容看成是纯粹的字符串信息,一对单引号之间可以包含更多的单引号。

you=”kkk”
echo  ‘this is just a ‘test’, can $you tell me the time ?’

将会显示this is just a ‘test’, can $you tell me the time ?, 它不会将$you替换成“kkk“, 同时‘test’也是作为字符串内容来处理的。

(b)双引号“ : 它将双引号之间的特殊字符作为shell中的含义来解释。

$ file=unixshell
$ echo “the content of  ‘date’  is in  $file”

这个例子将会显示 the content of wed Aug 16 16:20:12 is in unixshell,这个例子中,’date’被解释成了当前时间的返回值,$file被解释成了unixshell字符串。

(c)反引号` 用它来赋值时,表示变量中保存的是执行对应命令的结果。

  name=`whoami`
  echo $name

这个时候显示的不是字符串whoami,而是执行字符串whoami的返回结果,当然,要先保证字符串是一个合法的命令。

变量的定义域

同其他的编程语言如C,pascal一样,shell的变量也有局部变量和全局变量的区别。通常在一个shell程序中,通过形如var1=abc方式定义的都是局部变量,只能在该shell程序的进程中起作用,要定义全局变量,需要在局部变量定义之后使用export 命令来将这个变量声明为全局的: export $var1

$  var1=csu
$  echo  $var1     
$  sh              
$  echo  $var1     
$  exit            
$  echo  $var1
$  export $var1
$  sh
$  echo  $var1

Shell中命令的位置变量

位置参数是一种在调用shell程序的命令行中按照各自的位置决定的变量,是在程序名之后输入的参数。位置参数之间用空格分隔,shell取第一个位置参数替换程序文件中的$1,第二个替换$2,依次类推。$0是一个特殊的变量,它的内容是当前这个shell程序的文件名,所以,$0不是一个位置参数,在显示当前所有的位置参数时是不包括$0的。

预定义变量

$# 位置参数的个数

$? 前一个命令返回的状态值

Shell中的变量替换

在shell编程中,有时候会遇到这种情况,一个变量在尚未赋值的时候,就被程序进行了输出处理,这样输出的变量将会得到一个空字符串的结果。为了避免这种情况的发生,shell中引入了变量替换的概念,在变量没有赋值的时候可以用一个预先定义的字符串来替换。

替换的形式有三种,列举如下:

  • $ {var:-word} 表示如果var已经被赋值,则取它的值,否则取word的值,但var不改变。
  • $ {var:=word} 表示如果var已经被赋值,则取它的值,否则取word的值,同时将word赋给 var。
  • $ {var:+word} 表示如果var已经被赋值,则取它的值,否则var变量置为空。

运算符

关系运算符 & 算术

关系运算符只支持数字,不支持字符串,除非字符串的值是数字。

下表列出了常用的关系运算符,假定变量 a 为 10,变量 b 为 20:

a=10
b=20

val=`expr $a + $b`
echo "a + b : $val"

val=`expr $a - $b`
echo "a - b : $val"

val=`expr $a \* $b`
echo "a * b : $val"

val=`expr $b / $a`
echo "b / a : $val"

val=`expr $b % $a`
echo "b % a : $val"

if [ $a == $b ]
then
   echo "a 等于 b"
fi
if [ $a != $b ]
then
   echo "a 不等于 b"
fi


if [ $a -eq $b ]
then
   echo "$a -eq $b : a 等于 b"
else
   echo "$a -eq $b: a 不等于 b"
fi
if [ $a -ne $b ]
then
   echo "$a -ne $b: a 不等于 b"
else
   echo "$a -ne $b : a 等于 b"
fi
if [ $a -gt $b ]
then
   echo "$a -gt $b: a 大于 b"
else
   echo "$a -gt $b: a 不大于 b"
fi
if [ $a -lt $b ]
then
   echo "$a -lt $b: a 小于 b"
else
   echo "$a -lt $b: a 不小于 b"
fi
if [ $a -ge $b ]
then
   echo "$a -ge $b: a 大于或等于 b"
else
   echo "$a -ge $b: a 小于 b"
fi
if [ $a -le $b ]
then
   echo "$a -le $b: a 小于或等于 b"
else
   echo "$a -le $b: a 大于 b"
fi

布尔运算符

下表列出了常用的布尔运算符,假定变量 a 为 10,变量 b 为 20:

运算符说明举例
!非运算,表达式为 true 则返回 false,否则返回 true。[ ! false ] 返回 true。
-o或运算,有一个表达式为 true 则返回 true。[ $a -lt 20 -o $b -gt 100 ] 返回 true。
-a与运算,两个表达式都为 true 才返回 true。[ $a -lt 20 -a $b -gt 100 ] 返回 false。
if [ $a != $b ]
then
   echo "$a != $b : a 不等于 b"
else
   echo "$a == $b: a 等于 b"
fi
if [ $a -lt 100 -a $b -gt 15 ]
then
   echo "$a 小于 100 且 $b 大于 15 : 返回 true"
else
   echo "$a 小于 100 且 $b 大于 15 : 返回 false"
fi
if [ $a -lt 100 -o $b -gt 100 ]
then
   echo "$a 小于 100 或 $b 大于 100 : 返回 true"
else
   echo "$a 小于 100 或 $b 大于 100 : 返回 false"
fi
if [ $a -lt 5 -o $b -gt 100 ]
then
   echo "$a 小于 5 或 $b 大于 100 : 返回 true"
else
   echo "$a 小于 5 或 $b 大于 100 : 返回 false"
fi

逻辑运算符

以下介绍 Shell 的逻辑运算符,假定变量 a 为 10,变量 b 为 20:

运算符说明举例
&&逻辑的 AND[[ $a -lt 100 && $b -gt 100 ]] 返回 false
||逻辑的 OR[[ $a -lt 100 || $b -gt 100 ]] 返回 true

字符串运算符

下表列出了常用的字符串运算符,假定变量 a 为 “abc”,变量 b 为 “efg”:

运算符说明举例
=检测两个字符串是否相等,相等返回 true。[ $a = $b ] 返回 false。
!=检测两个字符串是否不相等,不相等返回 true。[ $a != $b ] 返回 true。
-z检测字符串长度是否为0,为0返回 true。[ -z $a ] 返回 false。
-n检测字符串长度是否不为 0,不为 0 返回 true。[ -n “$a” ] 返回 true。
$检测字符串是否为空,不为空返回 true。[ $a ] 返回 true。
a="abc"
b="efg"

if [ $a = $b ]
then
   echo "$a = $b : a 等于 b"
else
   echo "$a = $b: a 不等于 b"
fi
if [ $a != $b ]
then
   echo "$a != $b : a 不等于 b"
else
   echo "$a != $b: a 等于 b"
fi

文件测试运算符

文件测试运算符用于检测 Unix 文件的各种属性。

属性检测描述如下:

操作符说明举例
-b file检测文件是否是块设备文件,如果是,则返回 true。[ -b $file ] 返回 false。
-c file检测文件是否是字符设备文件,如果是,则返回 true。[ -c $file ] 返回 false。
-d file检测文件是否是目录,如果是,则返回 true。[ -d $file ] 返回 false。
-f file检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。[ -f $file ] 返回 true。
-g file检测文件是否设置了 SGID 位,如果是,则返回 true。[ -g $file ] 返回 false。
-k file检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。[ -k $file ] 返回 false。
-p file检测文件是否是有名管道,如果是,则返回 true。[ -p $file ] 返回 false。
-u file检测文件是否设置了 SUID 位,如果是,则返回 true。[ -u $file ] 返回 false。
-r file检测文件是否可读,如果是,则返回 true。[ -r $file ] 返回 true。
-w file检测文件是否可写,如果是,则返回 true。[ -w $file ] 返回 true。
-x file检测文件是否可执行,如果是,则返回 true。[ -x $file ] 返回 true。
-s file检测文件是否为空(文件大小是否大于0),不为空返回 true。[ -s $file ] 返回 true。
-e file检测文件(包括目录)是否存在,如果是,则返回 true。[ -e $file ] 返回 true。

条件控制语句

if语句

注意:条件表达式要放在方括号之间,并且要有空格,例如: [$a==$b] 是错误的,必须写成 [ $a == $b ]。

if语句的分支可以有 无分支条件语句,二分支条件语句,多分支条件语句。 无分支条件语句格式如下:

if  [condition]  
then
    命令1
    命令2
    …
    命令n
fi

当条件condition为真时,执行then后面的所有命令,condition为假则执行fi后面的语句。

if [condition1]
    then
 elif [contition2]
    then
 elif [condition3]
     then
     …
else
   command_n
 fi

例:假设一个连续运行系统,将建立错误记录文件errorfile 并不断写入错误信息。现在要求编写一个shell程序来产生定时错误日志文件datelog,能在datelog 中体现每个时间段中的错误信息

# checkerr.sh To check error information with time stamp !!!
date >> datelog
if test –r errorfile
   then cat errorfile >> datelog
            rm errorfile
else
   echo “No error occurs during this hour!“ >> datelog
fi

case

 case语句的语法为:
  case word in
    模式1 ) 命令 ;;
    模式2 ) 命令 ;;
    模式3 ) 命令 ;;
  esac

注意,在case中,每个命名命令的结束用;;表示模式匹配已经完成,不再匹配其他的模式,相当于C中的break。

例:编写一段shell程序,根据执行时获取的当前时间显示不同的问候信息

# hello.sh
hour = `date +%H`
case $hour in
0[1-9] | 1[01] )  echo “Good morining !!” ;;
1[234567] ) echo “Good afternoon !!” ;;
*) echo “Good evening !! ” ;;
esac

循环语句

for

for的语法格式为:

  for var
   in list-of-vars
  do
     command1
     command2
     …
     commandn
  done

for的语法说明为:shell程序扫描变量列表list-of-vars,将其中的每一个字依次存放在var中,并执行do和done之间的语句。如果list-of-vars中有n个字,则这个for循环将执行n次。

cd $HOME
 for dir in cc work
 do
    echo “…. In $dir….”
    cd $dir
    for file in *.[c]
       do ls –l $file
    done
  cd
done 

while

while循环 while - do - done结构

    while  [condition]
    do
        command1
        command2
        ….. 
    done

until

until  [condition]
    do
    command1
    commandn
    done

函数

function name
{
    若干命令行
}

函数使用:

  1. 调用函数之前,必须先定义函数。
  2. 函数的参数的传递:functionname para1 para2 ….
  3. 在函数内部参数的读取:$0-$9 , $@(所有参数) $#(参数总个数)
  4. 函数的返回值:可能使用return命令返回数字值;要返回字符串值,可以字符串保存在一个全局性的变量中,该变量在函数结束后能被外界使用;如果没有使用return命令,则函数返回值是函数中最后执行的一条命令的退出状态码。
  5. 变量使用:函数内部声明的变量默认为全局变量,使用local关键字声明的变量为局部变量(如 local var=“var”)。如果局部变量与全局变量同名,则在函数内部局部变量覆盖全局变量。
  6. 返回值的获取,当执行完函数后,函数的返回值被存放在$?中,可以通过它来获取函数的返回值。

举例

#HELLO.sh
function hello( )
  {    
       echo “hi”
  }
hello
echo $?

funWithParam(){
    echo "第一个参数为 $1 !"
    echo "第二个参数为 $2 !"
    echo "第十个参数为 $10 !"
    echo "第十个参数为 ${10} !"
    echo "第十一个参数为 ${11} !"
    echo "参数总数有 $# 个!"
    echo "作为一个字符串输出所有参数 $* !"
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73

脚本、调试

脚本开头加

#!/usr/bin/env bash  # 指定执行shell是谁,这个是bash,是从env里找bash然后执行
# set -x # 用于调试

检测命令是否有结果的

docker -v
if [[ $? != 0 ]]; then
	echo "安装docker环境..."
fi

读取输入

    read yes
    if [ $yes=='y' ];then
        echo "设置完成"
        exit
    fi

link

ln -s "$from" "$to"

列表循环

  for pkg in ${pkgs[*]}
  do
    echo ${pkg}
    brew install ${pkg}
  done

Search

    Table of Contents