7.1退出状态
Linux程序执行完成,就会向Shell返回一个退出状态码,按照惯例,为0的状态码就表示程序执行成功,非0的表示失败。
7.2变量$?
Shell会将变量$?自动设置为最后一条命令的退出状态。可以通过echo命令打印该变量查看。
[root@centos7_c1 linux]# ls
intro introo intros ison names script
[root@centos7_c1 linux]# cp intro introbak
[root@centos7_c1 linux]# echo $?
0
[root@centos7_c1 linux]# cp intro1 intro2
cp: 无法获取"intro1" 的文件状态(stat): 没有那个文件或目录
[root@centos7_c1 linux]# echo $?
1
[root@centos7_c1 linux]#
下面我们创建一个shell文件,运行查看指定名称的用户是否已登录。
不妨命名该文件为:
on_v1
通过vim编辑内容
[root@centos7_c1 linux]# vim on_v1
[root@centos7_c1 linux]# cat on_v1
#
#确定用户是否已经登录
#
user="$1"
if who | grep "$user"
then
echo "$user is logged on"
fi
[root@centos7_c1 linux]#
接下来测试一下,
[root@centos7_c1 linux]# who
chase pts/0 2019-07-08 10:55 (172.16.80.1)
root pts/1 2019-07-08 11:07 (172.16.80.1)
[root@centos7_c1 linux]# ./on_v1 chase
bash: ./on_v1: 权限不够
[root@centos7_c1 linux]# chmod +x on_v1
[root@centos7_c1 linux]# ./on_v1 chase
chase pts/0 2019-07-08 10:55 (172.16.80.1)
chase is logged on
[root@centos7_c1 linux]# ./on_v1 qiao
[root@centos7_c1 linux]# ./on_v1 cha
chase pts/0 2019-07-08 10:55 (172.16.80.1)
cha is logged on
[root@centos7_c1 linux]#
通过以上的测试命令,首先要赋予用户可执行on_v1文件的权限。我们只是想查看指定的用户是否已经登录,但是从shell的输出结果上看,它还给我们输出多了一行这样的:
chase pts/0 2019-07-08 10:55 (172.16.80.1)
哪怕我们根本就不想输出这行。这是因为grep不仅会在管道中返回退出状态,而且还会将匹配的行写入到标准输出。解决这个问题,我们可以把grep的输出重定向到系统的“垃圾桶”:/dev/null。这是一个特殊的系统文件,任何人都可以读取(立刻会得到一个EOF)或写入。向该文件写入的任何东西都会消失,就像一个巨大的黑洞一样。
who | grep "$user" > /dev/null
这样就可以解决这个问题了。
还有第二个问题,我想眼快的读者已经发现了:
[root@centos7_c1 linux]# ./on_v1 cha
chase pts/0 2019-07-08 10:55 (172.16.80.1)
cha is logged on
我们只是输入用户cha,但是控制台给我们输出了已经登录的chase用户,这个问题我们就通过正则来解决吧:
"^$user "
前面加^,后面加空格。
通过cat查看修改后的on程序,这次命名为on_v2
[root@centos7_c1 linux]# cat on_v2
#
#确定用户是否已经登录
#
user="$1"
if who | grep "^$user " > /dev/null
then
echo "$user is logged on"
fi
查看当前登录的用户。
[root@centos7_c1 linux]# who
chase pts/0 2019-07-08 10:55 (172.16.80.1)
root pts/1 2019-07-08 11:07 (172.16.80.1)
测试修改后的效果。
[root@centos7_c1 linux]# ./on_v2 chase
chase is logged on
[root@centos7_c1 linux]# ./on_v2 cha
[root@centos7_c1 linux]#
7.3 test命令
test的一般格式:
test expression
例子:
[root@centos7_c1 linux]# symbol=abc
[root@centos7_c1 linux]# echo KaTeX parse error: Expected 'EOF', got '#' at position 35: …ntos7_c1 linux]#̲ test -z "symbol"
[root@centos7_c1 linux]# echo KaTeX parse error: Expected 'EOF', got '#' at position 28: …ntos7_c1 linux]#̲ test的另一种格式: …symbol" ]
[root@centos7_c1 linux]# echo $?
1
[root@centos7_c1 linux]#
注意:这种格式在[之后和]之前必须要有空格。
字符串操作符:
操作符 | 如果满足一下条件,则返回真(退出状态码为0) |
---|---|
string1 = string2 | string1等于string2 |
string1 != string2 | string1不等于string2 |
string | string不为空 |
-n string | string不为空(test必须能够识别出作为参数的string) |
-z string | string为空(test必须能够识别出作为参数的string) |
整数操作符:
操作符 | 如果满足一下条件,则返回真(退出状态码为0) |
---|---|
int1 -eq int2 | int1等于int2 |
int1 -ge int2 | int1大于或等于int2 |
int1 -gt int2 | int1大于int2 |
int1 -le int2 | int1小于或等于int2 |
int1 -lt int2 | int1小于int2 |
int1 -ne int2 | int1不等于int2 |
文件操作符:
操作符 | 如果满足一下条件,则返回真(退出状态码为0) |
---|---|
-d file | file是一个目录 |
-e file | file存在 |
-f file | file是一个普通文件 |
-r file | file可由进程读取 |
-s file | file不是空文件 |
-w file | file可由进程写入 |
-x file | file可由进程执行 |
-L file | file是一个符号链接 |
逻辑否定操作符!
一元逻辑否定操作符!可以放置在任意的test表达式之前,否定该表达式的求值结果。例如:
[ ! -r /usrs/chase/phonebook ]
逻辑“与”操作符-a
操作符-a在两个表达式之间执行逻辑“与”运算,仅当这两个表达式均为真时,才返回真。
[ -f “
m
a
i
l
f
i
l
e
"
−
a
−
r
"
mailfile" -a -r "
mailfile"−a−r"mailfile” ]
逻辑“或”操作符为-o
括号
由于表达式中符号优先级的关系,有时要借助括号。
例子:
[ “
c
o
u
n
t
"
−
g
e
0
−
a
"
count" -ge 0 -a "
count"−ge0−a"count” -lt 10 ]
可以改写为:
[ ( “KaTeX parse error: Can't use function '\)' in math mode at position 14: count" -ge 0 \̲)̲ -a \( "count” -lt 10 ) ]
7.4 else
if命令中可以加入else,其一般格式为:
if commandt
then
command
command
...
else
command
command
...
fi
例子:
[root@centos7_c1 linux]# cat on_v3
#
#确定用户是否已经登录
#
user="$1"
if who | grep "^$user " > /dev/null
then
echo "$user is logged on"
else
echo "$user is not logged on"
fi
[root@centos7_c1 linux]# who
chase pts/0 2019-07-08 10:55 (172.16.80.1)
root pts/1 2019-07-08 11:07 (172.16.80.1)
[root@centos7_c1 linux]# ./on_v3 chase
chase is logged on
[root@centos7_c1 linux]# ./on_v3 tom
tom is not logged on
[root@centos7_c1 linux]#
实际上这个程序输入非一个参数是有问题的:
[root@centos7_c1 linux]# ./on_v3 chase tom
chase is logged on
[root@centos7_c1 linux]#
优化一下,cat查看优化后的内容
[root@centos7_c1 linux]# cat on_v4
#
#确定用户是否已经登录
#
if [ "$#" -ne 1 ]
then
echo "Incorrect number of arguments"
echo "Usage: on user"
else
user="$1"
if who | grep "^$user " > /dev/null
then
echo "$user is logged on"
else
echo "$user is not logged on"
fi
fi
[root@centos7_c1 linux]# ./on_v4 chase root
Incorrect number of arguments
Usage: on user
[root@centos7_c1 linux]# ./on_v4 chase
chase is logged on
[root@centos7_c1 linux]#
7.5 exit命令
shell内建的exit命令可以立刻终止shell程序的执行。其一般格式为:
exit n
其中n是你要返回的状态码。如果没有指定,则使用在exit之前最后执行的那条命令的退出状态(其实就是 exit $?)。
举例说明
有从电话薄中删除联系人程序,通过cat查看源码:
[root@centos7_c1 linux]# cat rem_v1
#
#从电话薄中删除联系人
#
grep -v "$1" phonebook > /tmp/phonebook
mv /tmp/phonebook phonebook
[root@centos7_c1 linux]#
优化一下,检查参数格式,
[root@centos7_c1 linux]# cat rem_v2
#
#从电话薄中删除联系人
#
if [ "$#" -ne 1 ]
then
echo "Incorrect number of arguments."
echo "Usage: rem name"
exit 1
fi
grep -v "$1" phonebook > /tmp/phonebook
mv /tmp/phonebook phonebook
[root@centos7_c1 linux]#
7.6 elif
elif的一般格式为:
if command1
then
command
command
...
elif command2
then
command
command
...
else
command
command
...
fi
下面给出一个根据不同时间段问候的案例,
[root@centos7_c1 linux]# cat greetings
#
#打印欢迎信息
#
#hour=$(date | cut -c12-13)
hour=$(date +%H)
if [ "$hour" -ge 0 -a "$hour" -le 11 ]
then
echo "Good morning"
elif [ "$hour" -ge 12 -a "$hour" -le 17 ]
then
echo "Good afternoon"
else
echo "Good evening"
fi
[root@centos7_c1 linux]#
执行效果
[root@centos7_c1 linux]# ./greetings
Good afternoon
[root@centos7_c1 linux]#
通过elif再优化一下rem程序,查看
[root@centos7_c1 linux]# cat rem_v3
#
#从电话薄中删除联系人
#
if [ "$#" -ne 1 ]
then
echo "Incorrect number of arguments."
echo "Usage: rem name"
exit 1
fi
name=$1
#
#找出匹配条目数量
#
matches=$(grep "$name" phonebook | wc -l)
#
#
#
if [ "$matches" -gt 1 ]
then
echo "More than one match; please qualify further"
elif [ "$matches" -eq 1 ]
then
grep -v "$name" phonebook > /tmp/phonebook
mv /tmp/phonebook phonebook
else
echo "I couldn't find $name in the phone book"
fi
[root@centos7_c1 linux]#
7.7 case
case 命令可以将单个值与一组值或表达式进行比较,在有匹配的时候执行一个或多个命令。其一般格式为:
case value in
pattern1) command
command
…
command;;
pattern2) command
command
...
command;;
…
pattern3) command
command
…
command;;
esac
value会连续和pattern1、pattern2…patternn比较,直到找到匹配项。接着,执行所匹配值之后的命令,碰到双分号后停止,双分号在这里起到break语句的作用。如果没找到匹配项,case中的命令一个都不执行。下面给出一个从数字翻译成英语的例子:
[root@centos7_c1 linux]# cat number
#
#将数字翻译成英语
#
if [ "$#" -ne 1 ]
then
echo "Uage: number digit"
exit 1
fi
case "$1"
in
0) echo zero;;
1) echo one;;
2) echo two;;
3) echo three;;
4) echo four;;
5) echo five;;
6) echo six;;
7) echo seven;;
8) echo eight;;
9) echo nine;;
esac
[root@centos7_c1 linux]#
特殊的模式匹配字符
调试选项 -x
[root@centos7_c1 linux]# sh -x number 5
+ '[' 1 -ne 1 ']'
+ case "$1" in
+ echo five
five
[root@centos7_c1 linux]#
7.8 空命令:
什么都不做。