第二章 shell程序设计
创建脚本示例
脚本内容
#!/bin/sh
#first
#it's am example for perfectxhj
for file in *
do
if grep -q POSIX $file
then
echo $file
fi
done
exit 0
其中,exit返回的是一个退出码,当此脚本被其他脚本调用时,退出码就可以被返回以查看。0表示成功。
设定为可执行
/bin/sh first
使用: chmod +x first 可以让所有用户都能执行这个文件。(让程序变为可执行文件)
./first 亦可以运行该程序,同时可以将脚本的完整相对路径告诉shell。
2.6 shell的语法
变量
在shell中,可以通过在变量名前加上$符号来访问它的内容。而为变量赋值时,只需使用变量名就可以被自动创建。
如:
test=Hello
echo $test
输出: Hello
注:如果字符串中包含空格,就要把他们用括号括起来。同时等号两边不能有空格。
read命令可以接收用户要输入的数据,按下回车键,则read命令结束。如下所示:
root@xhj-2:/usr/linuxProgramming# read what
perfectxhj
root@xhj-2:/usr/linuxProgramming# echo $what
perfectxhj
1.引号的使用
在脚本文件中,一个变量如果放在双引号里,程序执行时会自动替换其为它的值,如果在单引号里面,就不会发生替换。同时,在$变量前面加上\可以取消其特殊含义。
root@xhj-2:/usr/linuxProgramming# cat myvar
!/bin/sh
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
xixi
$myvar now equals xixi
2.环境变量
当一个shell脚本开始执行时,一些变量会根据环境设置中的值进行初始化。具体如下图所示:
实验:使用参数和环境变量
root@xhj-2:/usr/linuxProgramming# cat 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 directorory is $HOME"
echo "Please enter a new greeting"
read salutation
echo $salutation
echo "The script is now complete"
exit 0
输出如下所示:
root@xhj-2:/usr/linuxProgramming# ./try_var foo bar baz
Hello
The program ./try_var is now running
The second parameter was bar
The first parameter was foo
The parameter list was foo bar baz
The user's home directorory is /root
Please enter a new greeting
Sire
Sire
The script is now complete
这个实验创建变量并显示其内容,同时还显示了各种参数变量以及环境变量等。
实验:测试/bin/bash文件状态
root@xhj-2:/usr/linuxProgramming# cat filestatus
#!/bin/sh
if [ -f /bin/bash ]
then
echo "file /bin/bash exists"
fi
if [ -d /bin/bash ]
echo "/bin/bash is a directory"
else
echo "/bin/bash is not a directory"
fi
root@xhj-2:/usr/linuxProgramming# vim filestatus
root@xhj-2:/usr/linuxProgramming# ./filestatus
file /bin/bash exists
/bin/bash is not a directory
2.6.3 控制结构
if语句结构:
if condition
then
statements
else
statements
fi
实验:使用if语句
root@xhj-2:/usr/linuxProgramming# cat timeofday
#!/bin/sh
echo "Is it morning?Please answer yes or no"
read timeofday
if [ $timeofday = "yes" ]; then
echo "Good morning"
else
echo "Good afternoon"
fi
exit 0
实验:使用复杂if语句
root@xhj-2:/usr/linuxProgramming# cat timeofday
#!/bin/sh
echo "Is it morning?Please answer yes or no"
read timeofday
if [ $timeofday = "yes" ]; then
echo "Good morning"
elif [ $timeofday = "no" ]; then
echo "Good afternoon"
else
echo "U r wrong"
fi
exit 0
也就是说,在shell脚本中,所使用的的if语句结构为:
if语句结构:
if condition
then
statements
elif
statements
then
statements
else
statements
fi
for语句结构
for cvariable in values
do
statements
done
实验:使用for循环
root@xhj-2:/usr/linuxProgramming# cat forexample
#!/bin/sh
for foo in bar foos fud 4546
do
echo $foo
done
exit 0
实验:使用通配符拓展的for循环
本实验作用是用shell拓展把*拓展为当前目录中所有文件的名字,然后依次作为for循环中的变量$使用。
root@xhj-2:/usr/linuxProgramming# cat forex
#!/bin/sh
for file in $(ls h*.c)
do
echo $file
done
exit 0
while语句结构
for循环社适合于已知循环次数的情况,因为所有shell变量值都被认为是字符串,所以for循环特别适合于一些列字符串进行循环处理。但当实现不知道循环的次数,这时候就要用while循环了。
while condition do
statements
done
实验:密码检查程序
root@xhj-2:/usr/linuxProgramming# cat pwdchk
#!/bin/sh
echo "Enter your password"
read password
while [ "$password" != "secret" ]
do
echo "Sorry,try again"
read password
done
exit 0
until语句结构
until语句跟while循环很相似,只是把条件测试反过来了,循环将反复执行直到条件为真,在条件为真时反复执行。
until语句的语法如下所示:(感觉有点像 do ……while……)
until condition
do
statements
done
实验:设定警报,当特定用户登录时,警报启动。
#!/bin/bash
until who | grep "$1" > /dev/null
do
sleep 60
done
# now ring the bell and announce the expected user
echo -e '\a'
echo "*********$1 has just logged in"
exit 0
case结构
注:case中每个模式行都需要双分号来结尾。
case variable in
pattern [ | pattern ] …) statements;;
pattern [ | pattern ] …) statements;;
…
esac
实验:case1 用户输入
root@xhj-2:/usr/linuxProgramming# cat case1
#!/bin/bash
echo "Is it morning? Please answer yes or no"
read time
case "$time" in
yes) echo "Morning";;
no) echo "afternoon";;
*) echo "wrong";;
esac
exit 0
实验:case2 合并匹配模式
root@xhj-2:/usr/linuxProgramming# cat case2
#!/bin/bash
echo "Is it morning?Please answer yes or no"
read time
case "$time" in
yes | y | Yes |YES) echo "morning";;
n* | N* ) echo "afternoon";;
*) echo "wrong";;
esac
exit 0
实验:case3 执行多条语句
root@xhj-2:/usr/linuxProgramming# cat case3
#!/bin/bash
echo "Is it morning?"
read time
case "$time" in
yes | y |Yes |YES )
echo "morning!"
echo "Up bright and early this morning"
;;
[nN]*)
echo "Good afternoon"
;;
*)
echo "wrong"
echo "Please answer yes or no"
exit 1
;;
esac
exit 0
实验:AND列表
and列表也就是用一些列的&&符号来连接多个语句,只有这些语句都为真,整体的and列表才为真。同时只有前一个语句为真下一个被&&所连接的语句才会执行
root@xhj-2:/usr/linuxProgramming# cat and
#!/bin/bash
touch file_one
rm -f file_two
if [ -f file_one ] && echo "Hello" && [ -f file_two ] && echo "there"
then
echo "in if"
else
echo "in else"
fi
exit 0
输出:
Hello
in else
实验:OR列表
or列表允许我们持续执行一系列命令一直到有一条命令成功为止,成功后这条命令之后的命令将不再执行。
root@xhj-2:/usr/linuxProgramming# cat and
#!/bin/bash
rm -f file_one
if [ -f file_one ] || echo "Hello" || echo "there"
then
echo "in if"
else
echo "in else"
fi
exit 0
输出:
Hello
in if
函数
实验:一个简单的函数
root@xhj-2:/usr/linuxProgramming# cat function
#!/bin/bash
foo(){
echo "Function foo is executing"
}
echo "script starting"
foo
echo "script ended"
exit 0
输出:
script starting
Function foo is executing
script ended
注意:在调用一个函数之前,要先对其进行定义。shell脚本是从顶部开始执行的。
通过return可以返回数字值,字符值的返回可以利用变量来保存,该变量可以在函数结束之后被使用。同时也可以echo一个字符串并捕获其结果。
foo(){echo JAY;}
……
result="$(foo)"
注意:local关键字可以在shell函数中声明局部变量,该变量只在该函数中有效。若局部变量和全局变量同名,在该函数内部局部变量覆盖全局变量。
实验:变量作用域
root@xhj-2:/usr/linuxProgramming# cat variable
#!/bin/bash
sample_text="global variable"
foo(){
local sample_text="local variable"
echo "Function foo is executing"
echo $sample_text
}
echo "script starting"
echo $sample_text
foo
echo "script ended"
echo $sample_text
exit 0
输出:
script starting
global variable
Function foo is executing
local variable
script ended
global variable
实验:函数返回一个值
root@xhj-2:/usr/linuxProgramming# cat return
#!/bin/bash
yes_or_no(){
echo "Is your name $* ?"
while true
do
echo -n "Enter yes or no:"
read x
case "$x" in
y|yes) return 0;;
n|no ) return 1;;
*) echo "Answer yes or no"
esac
done
}
echo "Original parameters are $*"
if yes_or_no "$1"
then
echo "Hi $1,nice name"
else
echo "Never mind"
fi
exit 0
输出:
root@xhj-2:/usr/linuxProgramming# ./return hh hhh
Original parameters are hh hhh
Is your name hh ?
Enter yes or no:y
Hi hh,nice name
在这个程序中,首先定义了一个函数,但并不会立即执行。当执行到if时,首先把$1替换为脚本程序的第一个参数hh,再把它作为参数传递给这个函数。函数将使用这些参数并向调用者返回一个值。
break命令
break默认情况下跳出一层循环
root@xhj-2:/usr/linuxProgramming# cat break
#!/bin/bash
rm -rf fred*
echo > fred1
echo > fred2
mkdir fred3
echo > fred4
for file in fred*
do
if [ -d "$file" ]; then
break;
fi
done
echo " first dir starting fred was $file"
rm -rf fred*
exit 0
输出:
first dir starting fred was fred3
:命令
冒号是一个空命令,相当于true的别名,常用在
1.while循环的条件,如while:实现了一个无线循环,代替的是while true
2.用在变量的条件设置中,如:
:${var:=true}
示例:
root@xhj-2:/usr/linuxProgramming# cat maohao
#!/bin/bash
rm -f fred
if [ -f fred ]; then
:
else
echo file fred did not exist
fi
exit 0
输出:
file fred did not exist
:continue命令
该命令使for、while或者until循环跳到下一次循环继续执行,循环变量取循环列表中的下一个值。
root@xhj-2:/usr/linuxProgramming# cat continue
#!/bin/bash
rm -rf fred*
echo > fred1
echo > fred2
mkdir fred3
echo > fred4
for file in fred*
do
if [ -d "$file" ]; then
echo "skipping dir $file"
continue
fi
echo file is $file
done
rm -rf fred*
exit 0
输出:
root@xhj-2:/usr/linuxProgramming# ./continue
file is fred1
file is fred2
skipping dir fred3
file is fred4
.命令
用来在当前shell中执行命令。
作用类似于C语言中的#include指令。
eval命令
用来对参数求值。
foo=10
x=foo
y='$'$x
echo $y
输出$foo
foo=10
x=foo
eval y='$'$x
echo $y
输出10
export命令
将作为它参数的变量导出到子shell中,并使之在子shell中有效。
expr命令
将它的参数当做一个表达式来求值。
set命令
为shell设置参数变量。
grep命令
grep代表的是通用正则表达式解析器。
grep命令使用一个选项、一个要匹配的模式和要搜索的文件,语法:
grep [options] PATTERN [FILES]
2.6.6命令的执行
1.算术拓展
将准备求值的表达式括在$((……))中能有效完成简单的算术运算。
root@xhj-2:/usr/linuxProgramming# cat suanshu
#!/bin/bash
x=0
while [ "$x" -ne 10 ];do
echo $x
x=$(($x+1))
done
exit 0
输出是:
0
1
2
3
4
5
6
7
8
9
注:
-eq:等于
-ne:不等于
-le:小于等于
-ge:大于等于
-lt:小于
-gt:大于
2.参数拓展
root@xhj-2:/usr/linuxProgramming# cat canshu
#!/bin/bash
unset foo
echo ${foo:-bar}
foo=fud
echo ${foo:-bar}
foo=/usr/bin/X11/startx
echo ${foo#*/}
echo ${foo##*/}
bar=/usr/local/etc/local/networks
echo ${bar%local*}
echo ${bar%%local*}
exit 0
输出:
bar
fud
usr/bin/X11/startx
startx
/usr/local/etc/
/usr/
注:unset是从shell中删除对应的变量