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