1 shell中的控制语句
1.1 if/elif/else语句使用
需要注意的是if语句有很多空格,漏掉就会报错。
一、if语句
用法1:
if [ 判断条件 ]
then
语句块;
fi
用法2:
if [ 判断条件 ]
then
语句块1;
elif [ 判断条件 ]
then
语句块2;
else
语句块n;
fi
用法3:
if ((判断条件,可以按C的格式写))
then
语句块;
fi
1.2 case/in语句
-
匹配项可以是统配符号
-
*
通配符号:匹配任意多个字符 -
[a-z]
通配符:匹配a-z中的任意一个字符[0-9]
:匹配0-9中的任意一个字符[^345]
: 匹配一个除345之外的任意一个字符 -
?
通配符:表示匹配任意的一个字符 -
匹配项可以多个:
"YES"|"yes"|"y"|"Y")
-
case $变量 in
匹配项1)
语句块1
;;
匹配项2)
语句块2
;;
*)
语句块n;
;;
esac
案例代码:
#!/bin/bash
read -p "input year month > " year month
if ((year < 0 || month < 1 || month > 12))
then
echo "输入的年或月不正确"
exit
fi
case $month in
1|3|5|7|8|10|12)
echo "$year-$month有:31天"
;;
4|6|9|11)
echo "$year-$month有:30天"
;;
2)
if ((((year%4==0)&&(year%100!=0))||((year%400)==0)))
then
echo "$year-$month有:29天"
else
echo "$year-$month有:28天"
fi
;;
*)
echo "输入错误,请重试"
;;
esac
1.3 while循环语句
#用法1
while [ 循环条件 ]
do
循环体 #如果循环条件为真循环体执行
done
#用法2
while true
do
循环体 #死循环
done
#用法3
while ((循环条件))
do
循环体 #如果循环条件为真循环体执行
done
1.4 for循环
#用法1 (类似c语言的写法)
for ((i=0;i<10;i++))
do
循环体
done
#用法2
for 变量 in 单词列表(以空格分隔的字符串)
do
循环体
done
#用法3
for 变量 #在执行脚本的时候可以传参,这个参数会作为for循环的单词列表
do
循环体
done
1.5 select/in循环
select 变量 in 单词列表
do
循环体
done
1.5.1 select/in案例
#!/bin/bash
PS3="input > " #系统的环境变量,默认值是#?,可以修改成任意格式
select var in abc 123 def
do
echo "$var" #用户选择哪个单词,echo就输出哪个参数
done
执行效果:
linux@ubuntu:~/work/day4$ bash 09select.sh
1) abc
2) 123
3) def
input > 1
abc
input > 2
123
input > 3
def
input > #这里可以输入ctrl+d或ctrl+c结束选择
#ctrl+d结束select/in语句
#ctrl+c结束整个程序
1.6 shell中的break和continue
shell中的break是用于退出循环的,break的语法格式
break n
退出n层循环
#!/bin/bash
while true
do
i=0
echo "这是外循环"
sleep 1
while true
do
((i++))
echo "这是内循环"
sleep 1
if ((i==5))
then
break 2 #退出就近的两层循环
fi
done
done
continue结束本次循环进而执行下一次循环,continue的语法格式
continue n
#!/bin/bash
i=1
sum=0
while [ $i -le 100 ]
do
echo "这是外循环,i=$i"
while [ $i -le 100 ]
do
if ((i%2!=0))
then
((i++))
continue 2 #结束本次循环,进而执行最外层的下一次循环
fi
((sum+=i++))
done
done
echo $sum
2 不同对象的判断方法
(1)字符串对象(一定要注意在进行字符串的判断的时候都需要加上"")
-z 判断字符串是否为空
-n 判断字符串是否为非空
=或== 都是用来判读字符串是否相等
!= 不等于
\> 大于 (防止误认为重定向)
\< 小于
练习1:输入两个字符串,判断大小
(2)数字对象
-eq : 等于
-ne : 不等于
-gt : 大于
-lt : 小于
-ge : 大于等于
-le : 小于等于
练习2:请输入一个学生的成绩,判断学生等级
练习3:输入年份,判断平闰年
(3)文件属性
-b filename 判断文件是否存在,是否是块设备
-c filename 判断文件是否存在,是否是字符设备
-d filename 判断文件是否存在,是否是目录
-f filename 判断文件是否存在,是否是普通文件
-p filename 判断文件是否存在,是否是管道文件
-L filename 判断文件是否存在,是否是链接文件 (经测试链接文件也是普通文件)
-S filename 判断文件是否存在,是否是套接字文件
-e filename 判断文件是否存在
-s filename 判断文件是否存在,判断文件是否为空
练习4:输入文件名,输出文件的类型
(4)文件权限
-r filename 判断文件是否存在,是否有可读权限
-w filename 判断文件是否存在,是否有可写权限
-x filename 判断文件是否存在,是否有可执行权限
练习5:输入文件名判断文件是否有可写权限,如果没有给它加上
可写权限,然后向文件最后追加一句话
(5)文件比较
-nt 文件是否更新
-ot 文件是否更旧
-ef 文件的inode是否一致
(6)逻辑运算
-a 与
-o 或
! 非
3 shell中函数的介绍
-
function修饰函数,可以省略,但习惯上不省略
-
函数名的命令规则和c语言函数的命名规则一样
-
shell中所有的函数都没有参数列表,但是可以传参
在函数内可以通过位置变量获取给函数传递的参数
$0
:脚本名$1
:函数的第1个参数$2
:函数的第2个参数${n}
:函数的第n个参数$#
:函数参数的个数$@
或$*
:给函数传递的所有的参数 -
函数体都需要写在{}内
-
在shell中可以通过return返回[0-255]的结果,如果要返回其他结果通过echo完成
-
shell中的函数不会自动执行,只有调用函数的时候函数才会执行。
函数名 参数列表
function 函数名()
{
#函数体
return 结果;
}
3.1 shell函数的案例
1.通过return返回结果的实例
#!/bin/bash
#封装了求和的函数
function add()
{
#sum变量默认是全局变量,如果想要让sum变为局部变量需要local修饰
local sum=0
((sum=$1+$2))
return $sum #return返回的结果只能是[0-255]之间的数
}
#调用函数
add 11 22
#echo $sum
echo $? #获取上一步函数执行的结果
2.通过echo加命令置换可以返回结果的实例
#!/bin/bash
function add()
{
local sum=0
((sum=$1+$2))
echo $sum
}
ret=`add 255 255` #将echo命令执行的结果命令置换给了ret变量,这里就没有0-255的限制了
echo $ret
3.2 shell函数的练习
1.编写一个加法器的函数,在执行脚本的时候可以传递参数,用户可以输入任意多个参数,让它们求和后输出结果
#!/bin/bash
function add()
{
local sum=0
for var in $@ #接收传递给函数的所有参数
do
((sum+=var))
done
echo $sum
}
ret=`add $@` #接收终端传递过来的所有参数,然后把它们传递给函数
echo $ret
2.封装打印二进制的函数
#!/bin/bash
function print_bin()
{
local result="0b"
local flags=0
#可以通过$1获取num的结果
for ((i=0;i<32;i++))
do
if ((($1<<i)&0x80000000))
then
result="${result}1"
flags=1
else
if [ $flags -eq 1 ]
then
result="${result}0"
fi
fi
done
echo $result
}
read -p "input num > " num
result=`print_bin $num`
echo $result
3.输入用户名判断用户是否存在,如果存在就将用户的uid和gid输出
#!/bin/bash
function check_user()
{
local line=0
line=`grep "^$1" -nw /etc/passwd|cut -d ":" -f 1`
echo $line
}
function get_user_info()
{
local info=0
info=`head -$1 /etc/passwd | tail -1 | cut -d : -f 3,4`
echo $info
}
read -p "input username > " usrname
if [ -n "$usrname" ]
then
line=`check_user $usrname`
if [ -n "$line" ]
then
echo "查询的用户${usrname}存在"
info=`get_user_info $line`
echo "查询到用户的UID:GID是=> $info"
else
echo "查询的用户不存在,请重试"
fi
else
echo "输入错误,请重试"
exit
fi
4 练习代码
1.使用if判断字符串是否相等
#!/bin/bash
read -p "input str1 > " str1
read -p "input str2 > " str2
if [ -z "$str1" -o -z "$str2" ]
then
echo "input empty error,try again"
exit
fi
if [ "$str1" = "$str2" ]
then
echo "str1 = str2"
elif [ "$str1" \> "$str2" ]
then
echo "str1 > str2"
else
echo "str1 < str2"
fi
2.请输入一个学生的成绩,判断它是哪个等级,将学生等级输出到终端
#!/bin/bash
read -p "input score > " score
if [ -z "$score" ]
then
echo "学生成绩不能是空,请重试"
exit
else
if [ $score -lt 0 -o $score -gt 100 ]
then
echo "学生成绩的范围[0-100],输入错误,请重试"
exit
fi
fi
if [ $score -ge 90 ]
then
echo "A"
elif [ $score -ge 80 ]
then
echo "B"
elif [ $score -ge 70 ]
then
echo "C"
elif [ $score -ge 60 ]
then
echo "D"
else
echo "E"
fi
3.输入年份,判断平闰年
判断方法:如果能被4整除不能被100整除或者能被400整除的年是闰年
#!/bin/bash
read -p "input year > " year
if [ -z "$year" ]
then
echo "输入的年份不能为空"
exit
fi
#if [ $((year%4)) -eq 0 -a $((year%100)) -ne 0 -o $((year%400)) -eq 0 ]
if (( ((year%4==0)&&(year%100!=0))||(year%400==0) ))
then
echo "闰年,366天"
else
echo "平年,365天"
fi
4.输入文件名,输出文件的类型
#!/bin/bash
read -p "input file > " file
if [ -z "$file" ]
then
echo "输入的文件名为空,请重试"
exit
fi
if [ -f $file ]
then
echo "$file是普通文件"
fi
5.输入文件名判断文件是否是普通文件,如果是普通文件判断是否有可写权限,如果没有给它加上
可写权限,然后向文件最后追加"hello world"
#!/bin/bash
read -p "input filename > " file
if [ -z "$file" ]
then
echo "输入为空,请重试"
exit
fi
if [ -f $file ]
then
if [ ! -w $file ]
then
chmod u+w $file
fi
echo "hello world" >> $file
else
echo "$file不存在或不是普通文件,请重试"
fi
6.判断文件时间戳新旧
#!/bin/bash
read -p "input file1 > " file1
read -p "input file2 > " file2
if [ $file1 -nt $file2 ]
then
echo "$file1新于$file2"
else
echo "$file1旧于$file2"
fi
7.判断用户家目录下是否存在file-dir和dir-dir目录,如果不存在就创建,如果存在就清空
向脚本输入任意一个路径,将这个路径下的文件拷贝到file-dir下将目录拷贝到dir-dir下
输出拷贝的文件的个数和目录的个数
#!/bin/bash
arr=("/home/linux/file-dir" "/home/linux/dir-dir")
n=${#arr[*]}
i=0
while [ $i -lt $n ]
do
if [ -d ${arr[$i]} ]
then
echo "目录存在,清除了目录下的所有文件"
rm -rf ${arr[$i]}
mkdir ${arr[$i]}
else
if [ -e ${arr[$i]} ]
then
echo "存在了其他类型的文件,已移除${arr[$i]}"
rm -rf ${arr[$i]}
fi
echo "新建了${arr[$i]}目录"
mkdir ${arr[$i]}
fi
((i++))
done
read -p "input path> " path
if [ -d $path ]
then
file_arr=(`ls $path`)
x=${#file_arr[*]}
j=0
f=0
d=0
while [ $j -lt $x ]
do
if [ -f $path/${file_arr[$j]} ]
then
cp $path/${file_arr[$j]} ${arr[0]}
((f++))
elif [ -d $path/${file_arr[$j]} ]
then
cp $path/${file_arr[$j]} ${arr[1]} -r
((d++))
fi
((j++))
done
else
echo "输入的路径错误,请重试"
exit
fi
echo "拷贝的文件的个数:$f"
echo "拷贝的目录的个数:$d"
8.使用shell脚本编写一个实时时钟代码
#!/bin/bash
year=2024
month=2
day=29
hour=23
min=59
sec=55
clear
while true
do
((sec++))
if [ $sec -ge 60 ]
then
((sec=0))
((min++))
if [ $min -ge 60 ]
then
((min=0))
((hour++))
if [ $hour -ge 24 ]
then
((hour=0))
((day++))
case $month in
1|3|5|7|8|10|12)
if [ $day -gt 31 ]
then
((day=1))
((month++))
fi
;;
4|6|9|11)
if [ $day -gt 30 ]
then
((day=1))
((month++))
fi
;;
2)
if (((year%4==0 && year%100!=0)||(year%400==0)))
then
if [ $day -gt 29 ]
then
((day=1))
((month++))
fi
else
if [ $day -gt 28 ]
then
((day=1))
((month++))
fi
fi
;;
*)
echo "month error,try again"
exit
;;
esac
if [ $month -gt 12 ]
then
((month=1))
((year++))
fi
fi
fi
fi
printf "%d-%02d-%02d %02d:%02d:%02d\r" $year $month $day $hour $min $sec
sleep 1
done