几个Linux的Shell编程例子

前言

Shell 是一个用 C 语言编写的程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。

Shell 脚本,是一种为 shell 编写的脚本程序。业界所说的 shell 通常都是指 shell 脚本,但要注意的是,shell和shell script是两个不同的概念。由于习惯的原因,人们经常说的“shell编程”都是指 shell 脚本编程,而不是指开发 shell 自身。

Shell 编程跟Python、Php 等语言的编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以开始编程。

1 找出100以内的素数

只能被1和它本身整除的数称为素数。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/bash  
judge() #定义函数
{
i=2;
flag=1;
while [ $i -lt $num ] #从2开始循环检测小于num的所有正数,看是否能整除num
do
let "m=num%i" #计算表达式
if [ $m -eq 0 ]
then
flag=0; #标记出不是素数
break;
fi #闭合if
let "i=i+1"
done
if [ $flag -eq 1 ]
then
printf "%d " $num
fi
}
num=2
while [ $num -lt 100 ] #在100以内循环
do
judge #调用函数
let "num=num+1"
done

运行结果:

2 判断回文数

如果一个数的数字按相反的顺序排列后,得到数和原来的数一样,这个数就被叫做回文数。例入121,12321等等,而且个位数一定是回文数。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/bin/bash   
judge() #定义函数
{
x=$1 #传参
sum=0
origin=$x #引用前面定义过的变量要加$
while [ $x -ne 0 ] #中括号里面的字符不能紧贴中括号
do
let "num=x%10"
let "sum=sum*10+num"
let "x=x/10"
done
if [ $sum -eq $origin ]
then
echo "Yes"
else
echo "No"
fi
}

#主程序入口
#判断传参的合法性
if [ $1 -lt 0 ] #判断数字是否为负数
then
echo "the number is minus" >&2
exit 1
fi

judge $1 #输入1个参数,调用函数

运行结果:

3 判断整数是否规范

判断给出的整数是否符合规范,同时还可以如果同时给出三个参数,还可以判断第一个整数是否在第二和第三个整数之间。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/bin/bash  
judge() #定义函数
{
signed="" #初始化
integer=$1 min=$2 max=$3
#判断是否为负数,第一个字符是否为-。如是,则判断后面的是否为整数;若非负,则判断是否为整数。
if [ "$(echo $1 | cut -c1)" = "-" ]
then
signed="-"
integer="${integer#?}" #${variable#pattern}把variable中的内容去掉左边最短的匹配模式,?表示仅与一个任意字符匹配
fi

if [ -z "$integer" ] #只有一个符号没有数字是非法的
then
echo "Invalid input, just a '-' is not allowed" >&2 #>&2可以将错误输出指定文件。
return 1
fi
#判断是否都是数字组成。
if [ -n "$(echo $integer | sed 's/[[:digit:]]//g')" ] #判断是否为数字
then
echo "Invalid integer, it includes some char but digit" >&2
return 1
fi
integer="$signed$integer"
#范围判断,当min和max为空时(即未传范围),默认为$integer。
if [ $integer -lt ${min:=$integer} ] #-lt表示小于
then #":="代表若min值为空则赋值成默认的integer,若min已被赋值则为不再以integer赋值
echo "$integer is too small,it should greater than $min" >&2
return 1
fi
if [ $integer -gt ${max:=$integer} ] #-lt表示大于, ":="的用法同上
then
echo "$integer is too large,it should little than $max" >&2
return 1
fi
return 0
}

#主程序
#判断传参的合法性
if [ $1 -eq 0 ]
then
echo "you could not do nothing" >&2
exit 1
fi

if judge "$1" "$2" "$3" #三个参数,$2和$3表范围可以缺省
then
echo "your input integer is valid"
fi

运行结果:

4 判断日期

给出一个日期,能够判断当年是否为闰年和当月天数,并给出明天的日期。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#!/bin/sh  
judge_leap() #判断是否闰年
{ #expr是一个手工命令行计数器,可以求表达式变量的值
Y=`expr substr $1 1 4`
r1=`expr $Y \% 4` #if((year%4==0&&year%100!=0)||year%400==0)
r2=`expr $Y \% 100` #(1)普通年能被4整除且不能被100整除的为闰年,(2)世纪年能被400整除的是闰年。
r3=`expr $Y \% 400`

if [ "$r1" -eq 0 -a "$r2" -ne 0 -o "$r3" -eq 0 ];then #年月日同时不为0
FRUN="true"
else
FRUN="false"
fi
echo $FRUN
}

get_mon_days() # 获取当月天数
{
Y=`expr substr $1 1 4` #从$1中取出标号1-4的字符,得年份
M=`expr substr $1 5 2` #从$1中取出标号5-2的字符,得月份

case "$M" in #case语句来处理月份
01|03|05|07|08|10|12) days=31;;
04|06|09|11) days=30;;
02)
_tmpStr=`check_leap "$Y"` #判断是否闰年,调用函数
if [ "$_tmpStr" = "true" ] ; then
days=29
else
days=28
fi
;;
*)
days=0
;;
esac
echo $days
}

check_date() #检查日期格式(例:20141022)
{
[ $# -ne 1 ] && return 1 #检查是否传入一个参数

_lenStr=`expr length "$1"` #检查字符串长度
[ "$_lenStr" -ne 8 ] && return 1

_tmpStr=`echo "$1" | grep "^[^0][0-9]*$"` #检查是否输入的是非0开头的数字
[ -z "$_tmpStr" ] && return 1

Y=`expr substr $1 1 4`
M=`expr substr $1 5 2`
D=`expr substr $1 7 2`
[ "$M" -lt 1 -o "$M" -gt 12 ] && return 1 #检查月份
days=`get_mon_days "$Y$M"` #取当月天数
[ "$D" -lt 1 -o "$D" -gt "$days" ] && return 1 #检查日

return 0
}

get_next_date() #返回明天日期
{
Y=`expr substr $1 1 4`
M=`expr substr $1 5 2`
D=`expr substr $1 7 2`

dad=`get_mon_days "$Y$M"` #当月天数

if [ "$D" = "$dad" ];then #月底的情况
if [ "$M$D" = "1231" ];then #年底的情况
YY=`expr $Y + 1`
next_date="${YY}0101"
else
MM=`expr $M + 1`
MM=`printf "%02d" $MM`
next_date="$Y${MM}01"
fi
else
#通常情况
DD=`expr $D + 1`
DD=`printf "%02d" $DD`
next_date="$Y$M$DD"
fi

echo $next_date
}

#主程序

#处理MM/DD/YYYY 和MM-DD-YYYY 的形式
#set 的--命令可以将其后的参数赋予位置参数$1、$2和$3
set -- $(echo $1 | sed 's/[\/\-]/ /g')


#检查日期格式
_dateStr="$1$2$3"
check_date $_dateStr
if [ $? -eq 1 ];then #提示出错
echo "<ERROR>输入日期[$1]格式错误!示例:(`date +%Y%m%d`)"
exit 1
fi

cat <<EOF #输出
是否闰年: `judge_leap $_dateStr`
当月天数: `get_mon_days $_dateStr`
明天日期: `get_next_date $_dateStr`
EOF

运行结果:

参考:

[1] Shell教程. https://www.runoob.com/linux/linux-shell.html.

[2] Wicked Cool Shell Scripts, 2nd Edition.