day52


shell脚本


if分支结构


1) 格式
 

C语言:
if(条件1)
{
    执行的语句
}
else if()
{}
else
{}
 
shell中的if语句
[]本质上一个test指令,shel中if的条件由test指令完成
# 单分支结构
if [ test语句 ]    ---->   test 表达式
then
    语句块
fi
 
# 双分支结构
if [ test语句 ]    ---->   test 表达式
then
    语句块
else
    不满足
fi
 
# 多分支结构
if [ test语句1 ]    ---->   if test 表达式    --->  if [ 表达式 ]; then
then
    满足语句1执行的语句块
elif [ test语句2 ]    ---->   elif test 表达式    --->   elif test 表达式 ; then
then
    满足语句2执行的语句块
else
    都上都不满足
fi
 
# 类似于C语言的格式
if (( a == b ))
then
 
fi


2) if对整数进行判断


$?:获取上一个指令是否是正确的执行结果
0:真        非0:假
 

a -eq b           测试a和b是否相等       # equal
    test $a -eq $b
    echo $?    # 如果两个数相等则为真,反之为假
a -ne b           测试a和b是否不相等     # on equal
a -gt b           测试 a > b            # greater than
a -ge b           测试 a >= b           # greater equal than
a -lt b           测试 a < b            # less than
a -le b           测试 a <= b           # less equal than
 

read num1 num2
 
if [ $num1 -eq $num2 ] 
then 
    echo "num1 == num2" 
elif test $num1 -gt $num2    # [ $num1 -gt $num2 ] 
then 
    echo "num1 > num2" 
else 
    echo "num1 < num2" 
fi
 

3) if对字符串进行判断


如果使用 [] 代替test进行表达式的处理,在[]内,字符串需要加 ""(获取变量时)
 

s1 = s2           测试两个字符串内容是否完全一致
    test "hello" = "hello"
    echo $?       # 0     相等为真,不相等为假
    
s1 != s2          测试两个字符串是否内容有差异    # 相等为假,不相等为真
 
-z s1             测试s1字符串是否为空
    test -z ""
    echo $?           # 0    字符串没有长度,则为真
    test -z "hello"
    echo $?           # 1    字符串由长度,则为假 
 
-n s1             测试s1字符串是否不为空         # 字符串没有内容,则为假,反之为真

1、终端输入年份,判断闰平年
 

#!/bin/bash
 
read -p "请输入一个年份" year
 
# 判断平闰年
#if [ $((year%4)) -eq 0 -a $((year%100)) -ne 0 -o $((year%400)) -eq 0 ]    # 在一个test表达式中,使用 -a判断逻辑与,-o判断逻辑或
#if (( (year % 4 == 0 && year % 100 != 0) || year % 400 == 0 ))    # 使用C语言格式进行书写
if [ $((year%4)) -eq 0 ] && [ $((year%100)) -ne 0 ] || [ $((year%400)) -eq 0 ]
then
    echo "$year是闰年"
else
    echo "$year是平年"
fi


4) if对文件的判断
 

-d name        测试 name 是否为一个目录
    read FILE
    test -d $FILE
    echo $?    # 如果 name 是目录则为真,反之为假
-f name        测试 name 是否为一个普通文件     对软连接文件的判断也会成立
-e name        测试文件是否存在
 
-b name        测试 name 是否为一个块设备文件
-c name        测试 name 是否为一个字符设备文件
-h name 或者 -L name     测试 name 是否为一个软链接文件
-p name        测试 name 是否为一个管道文件
-S name        测试 name 是否为一个套接字文件
 
file1 -nt file2    测试1比2的时间戳更新
file1 -ot file2    测试1比2的时间戳更旧
 
-s name        测试文件大小是否不为0
 
-w name        测试文件是否存在可写权限
-r name        测试文件是否存在可读权限
-x name        测试文件是否存在可执行权限
练习:
1、在当前目录下,创建一个软链接文件,判断该软链接文件,是否是一个普通文件,如果是普通文件,判断是否有可执行权限。
 

#!/bin/bash
 
ln -s ./if.sh ./linkif.sh
filename=./linkif.sh
 
if [ -f "$filename" ]
then
    echo "$filename 是一个普通文件"    # 会打印输出,因为打开软链接文件实际上打开的是源文件
    if [ -x "$filename" ]
    then
        echo "有可执行权限"
    fi
fi
2、终端输入一个.c文件的文件名,判断文件是否存在,如果存在,判断文件是否有内容,如果有内容,编译该文件。
 

#!/bin/bash
 
read -p "请输入一个.c文件:" filename
 
if [ -e "$filename" ]
then
    if [ -s "$filename" ]
    then
        gcc $filename
    else
        echo "文件为空"
    fi
else
    echo "$filename不存在"
fi


 case...in分支结构


1) 复习C中switch...case
 

switch(变量)
{
    case 1:
        语句;
        break;
    default:
        语句;
}


2) case...in格式
 

case $变量名 in
    常量1)
        语句
        ;;        --->  和c中break的作用相同,shell中必须写;;
    常量2)
        语句
        ;;
    常量3)
        语句
        ;;
    *)          --->  起到通配符的作用,可以匹配所有情况,shell中 *) 必须是最后一条分支
        语句    --->  最后一个分支可以不写;;
esac
 


case...in中常用可能出现的情况:


1. 1): 如果变量的值为1,和这个分支匹配
2. 1|2|3|4): 当变量的值为1或2或3或4,都会走这个分支
3. [0-9]): 变量的值是0-9的范围内都走该分支        不能写两位数,都是对单个字符判断
4. 1?): 1开头的两个字符的情况
代码示例:
 

#!/bin/bash 
 
read -p "请输入一个数字:" num
 
case $num in 
1|2|3|4) 
    echo "1|2|3|4:  $num" 
    ;; 
2?) 
    echo "2?: $num" 
    ;; 
[5-9]) 
    echo "[5-9]:$num" 
    ;; 
3[0-9] | 40) 
    echo "大于等于30 $num" 
    ;; 
*) 
    echo "其他情况" 
esac


1、终端输入一个学生成绩,根据成绩高低分类,[100,90]A,[90,80]B,[80,70]C,[70,60]D,[60,0]不及格
 

#!/bin/bash
 
read -p "请输入分数" score
 
case $score in
9[0-9] | 100)
    echo A
    ;;
8[0-9])
    echo B
    ;;
7?)
    echo C
    ;;
6[0-9])
    echo D
*)
    echo "不及格"
esac
2、终端输入一个字母,判断是大写字母还是小写字母
 

#!/bin/bash
 
read -p "请输入字母" str
 
case $str in
[[:lower:]])
    echo "小写"
    ;;
[[:upper:]])
    echo "大写"
*)
    echo "输入错误"
esac


while循环结构


1) 格式
 

while [ test语句 ]    --->  while test 表达式
do
    语句块
done
代码示例:
 

#!/bin/bash 
 
i=1 
 
while [ $i -le 5 ] 
do 
    echo "hello world" 
    ((i++)) 
done


2) while嵌套格式
 

while [ test语句 ]
do
    while [ test语句 ]
    do
        语句块
    done
done

1、求1-100的和
 

#!/bin/bash
 
i=0
sum=0
while [ $i -le 100 ]
do
    ((sum+=i))
    ((i++))
done
echo $sum
2、终端输入数组,求数组中元素的和
 

#/bin/bash
 
read -a arr    # 终端输入的数组一定不是一个稀疏数组
len=${#arr[*]]}  # 数组长度
i=0    # 数组下标
sum=0  # 数组元素和
while [ $i -lt $len ]
do
    ((sum+=${arr[i]}))
    ((i++))
done
echo "数组和为: $sum"
 
3、终端输入行数,打印直角三角形
*
**
***
·····
 

#/bin/bash
 
read -p "请输入行数" line
i=1  // 行数
while [ $i -le line ]
do
    j=1
    while [ $j -le $i ]
    do
        echo -n "*"
        ((j++))
    done
    echo
    ((i++))
done


for循环结构


1) 格式
 

1. 类似于C语言的格式


for ((表达式1;表达式2;表达式3))
do
    语句
done
 


2. shell自己的格式


for 变量名 in 字符串列表
do
    语句
done
 
for i in aa bb cc dd
do
    echo $i
done 
执行逻辑:
循环变量i从in后面提供的字符串列表中,按顺序取值,
循环次数和字符串列表中字符串的个数有关,
直到i把字符串列表中每一个字符串的值都获取结束后,循环结束
 


3. 变量i从命令行中取值,省略in、单词表


for i 
do
    echo $i
done
 

2) 使用连续列表的情况
 

1. seq 起始值 间隔值 终止值    ---> 会将结果回显到终端的指令
如果想在for中使用这个指令,`seq 1 1 100`  --->  in 后面就是1-100的列表
2. {1..3} ---> 遍历1-3中的每一个数,
注意:{}中间是两个点,写三个点就失效了


1、终端输入行数,打印直角三角形
*
**
***
·····
 

#!/bin/bash
 
read -p "请输入行数" line
 
for (( ))
do
    for (( ))
    do
        echo
    done
    echo
done
 
2、求100-1000内的水仙花数
 

#!/bin/bash
 
sum=0
for (())
do
 
    if [  ]
    then
        echo 
    fi
done
 
3、使用for循环,统计家目录下普通文件和目录文件的个数,并输出
 

#!/bin/bash
 
dir_count=0
file_count=0
 
for filename in 
do
    if [  ]
    then
    
    elif [  ]
    then
    
    fi
done
echo $dir_count
echo $file_count
 

select..in语句


1) 格式
 

select 变量名 in 选项列表
do
    语句块
done 
 
select...in如何退出,可以直接ctrl c,或者在代码中运行exit
执行逻辑:
会在终端打印选项列表,用户需要根据选项前面的序号做出选择,选择后变量会获取到相应的值
如果用户不做选择,会再次打印选项列表,
如果用户选错,获取到空值


2) 和case...in结合
 

#!/bin/bash
 
select sub in 数学 英语 物理 化学 体育 Q
do 
    case $sub in 
    "数学") 
        echo "上数学" 
        ;; 
    "英语") 
        echo "上英语" 
        ;;
    "物理") 
        echo "上英语" 
        ;;
    "化学") 
        echo "上英语" 
        ;; 
    "q") 
        exit 
        ;;
    esac 
done 
 

辅助控制关键字


1) break
 

break 1;   --->  退出1层循环(1可以不写)
break n;   --->  退出n层循环


2) continue
 

continue 1   --->  退出1层本次循环
continue n   --->  退出n层本次循环,跳出n层循环时,只需看第n层循环是否有下一次即可
代码示例:
 

for ((i=0; i <5;i++)) 
do 
    for ((j=0;j<5;j++)) 
    do 
        if [ $j -eq 3 ] 
        then 
            # break 
            # break 2 
            # continue 
            continue 2 
        fi 
        echo "$i:$j" 
    done 
done


shell中的函数


1) 格式
 

function 函数名()    --->  function可以不写
{
    函数体
    return 返回值    ---> 函数是否有返回值,根据实际的实现来决定(0-255之间)
}
 
注意事项:
1、function在定义函数时,可以加也可以不加
2、shell中的函数是否有返回值,根据实际情况决定
3、shell中函数是否有参数根据实际的调用情况决定
4、shell中的函数仍然满足先定义,后调用的原则
5、()内必须为空,不能写任何内容
 
fun()
{
    
}
fun 1 2 3


2) 调用函数
 

直接通过函数名调用函数
函数名
如果函数需要外部传参:
函数名 参数1 参数2 参数3 ·····


3) 如何获取函数的外部参数
 

仍然通过位置变量获取:
$0    --->  获取的是脚本名
$n    --->  n的数值在10及以上需要加 ${}
 
脚本和函数的外部参数都通过位置变量获取,互不影响
1. 在函数内使用位置变量,获取的是函数的外部参数
2. 在脚本中使用位置变量,获取的是脚本的外部参数
3. 如果想要在函数中,使用脚本的外部参数,只能通过函数调用将该参数传给函数
代码示例:
 

#!/bin/bash 
 
function fun() 

    num=10 
    sum=$(($1+$2)) 

 
echo $sum 
echo $num   # 空 
fun 11 12   # 调用函数fun并传了两个参数到函数中 
echo $sum   # 在函数外可以访问函数内的变量,shell中变量全部都是全局变量 
echo $num   # 10, 因为调用过函数了num赋值过


4) 如何获取函数的返回值
 

shell中函数返回值通过 $? 获取,返回值只能是0-255范围内的数
$?获取返回返回值的本质:
$?是获取上一条指令的执行结果
 
 

#!/bin/bash 
 
function fun() 

    return 30 

fun
ret=$? 
echo ret=$ret
ret=fun    # 给ret变量赋值为fun字符串,并没有调用fun函数


5) 接收无返回值函数的结果
 

#!/bin/bash
 
fun()
{
    echo hello world
}
 
ret=`fun`    # 没有hello world输出在终端,因为echo的输出被命令置换符获取了,并且赋值给了变量
echo $ret


6) local在函数中的使用


修饰变量的关键字local:定义局部变量
 

function fun() 

    local num=10 
    sum=$(($1+$2)) 

 
fun 11 12   
echo $sum 
echo $num   # 空值,因为num是一个局部变量,不能在函数外被访问

c_count=0

# 遍历家目录下的所有文件和目录
for filename in ~/*; do
    if [ -c "$filename" ]; then
        ((c_count++))  # 增加字符设备文件计数
    fi
done

# 输出结果
echo "家目录下,c文件的个数为:$c_count"
declare -A arr=(
    [2]=9
    [4]=8
    [30]=23
    [24]=3
    [21]=7
)

# 函数计算稀疏数组的和
function sum_sparse_array() {
    declare -n input_array=$1  # 使用declare -n创建一个引用
    local sum=0

    # 遍历传入的稀疏数组
    for index in "${!input_array[@]}"; do
        ((sum += input_array[$index]))  # 累加每个元素的值
    done
    echo $sum  # 返回和
}

# 调用函数并输出结果
result=$(sum_sparse_array arr)  # 将数组名作为参数传递
echo "稀疏数组的和为: $result"

以下是C52 LED电子时钟设计的相关信息: 1. 该电子时钟采用STC89C52单片机和LED点阵显示,能够显示当前的月、日、时、分、秒,24小时制。 2. 月、日、时、分、秒均可以单独设置,设置时该项目闪烁。 3. 外接3个按键,一个用于选择需要设置的项目,一个增加、一个减少。 4. 该电子时钟基于定时器实现时间的计时,利用按钮调节模式切换,设置闹钟,调节时间等功能。 以下是C52 LED电子时钟设计的代码演示: ```c #include <reg52.h> #include <intrins.h> #define uchar unsigned char #define uint unsigned int uchar code table[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f}; // 数码管显示0~9的编码 uchar sec = 0, min = 0, hour = 0, day = 1, month = 1, year = 20; // 定义秒、分、时、日、月、年 uchar alarm_hour = 0, alarm_min = 0; // 定义闹钟的小时和分钟 uchar mode = 0; // 定义模式,0为时间模式,1为设置模式,2为闹钟模式 uchar set_pos = 0; // 定义设置的位置,0为设置小时,1为设置分钟,2为设置月份,3为设置日期,4为设置年份 uchar key_value = 0; // 定义按键值,0为没有按键按下,1为K1按下,2为K2按下,3为K3按下 sbit LSA = P2^2; // 数码管LSA引脚 sbit LSB = P2^3; // 数码管LSB引脚 sbit LSC = P2^4; // 数码管LSC引脚 sbit SDA = P3^4; // IIC总线数据线 sbit SCL = P3^5; // IIC总线时钟线 void delay(uint i) // 延时函数 { while(i--); } void write_byte(uchar dat) // 向IIC总线写入一个字节 { uchar i; for(i = 0; i < 8; i++) { SDA = dat >> 7; // 先发送高位 dat <<= 1; SCL = 1; _nop_(); _nop_(); SCL = 0; } SDA = 1; // 释放数据线 } uchar read_byte() // 从IIC总线读取一个字节 { uchar i, dat = 0; SDA = 1; // 先释放数据线 for(i = 0; i < 8; i++) { dat <<= 1; SCL = 1; _nop_(); _nop_(); dat |= SDA; // 读取数据线上的数据 SCL = 0; } return dat; } void iic_start() // IIC总线起始信号 { SDA = 1; SCL = 1; _nop_(); _nop_(); SDA = 0; _nop_(); _nop_(); SCL = 0; } void iic_stop() // IIC总线停止信号 { SDA = 0; SCL = 1; _nop_(); _nop_(); SDA = 1; _nop_(); _nop_(); } void ds1307_write(uchar addr, uchar dat) // 向DS1307写入一个字节 { iic_start(); write_byte(0xd0); // 发送写地址 write_byte(addr); // 发送寄存器地址 write_byte(dat); // 发送数据 iic_stop(); } uchar ds1307_read(uchar addr) // 从DS1307读取一个字节 { uchar dat; iic_start(); write_byte(0xd0); // 发送写地址 write_byte(addr); // 发送寄存器地址 iic_start(); write_byte(0xd1); // 发送读地址 dat = read_byte(); // 读取数据 iic_stop(); return dat; } void init_ds1307() // 初始化DS1307 { ds1307_write(0x00, 0x00); // 秒清零 ds1307_write(0x01, 0x00); // 分钟清零 ds1307_write(0x02, 0x00); // 小时清零 ds1307_write(0x03, 0x01); // 星期一 ds1307_write(0x04, 0x01); // 1号 ds1307_write(0x05, 0x01); // 1月 ds1307_write(0x06, 0x21); // 2021年 } void display_time() // 显示时间 { uchar i; uchar dis_buf[8] = {0}; // 显示缓存 dis_buf[0] = table[hour / 10]; dis_buf[1] = table[hour % 10]; dis_buf[2] = 0x40; dis_buf[3] = table[min / 10]; dis_buf[4] = table[min % 10]; dis_buf[5] = 0x40; dis_buf[6] = table[sec / 10]; dis_buf[7] = table[sec % 10]; for(i = 0; i < 8; i++) { switch(i) { case(0): LSA = 0; LSB = 0; LSC = 0; break; case(1): LSA = 1; LSB = 0; LSC = 0; break; case(2): LSA = 0; LSB = 1; LSC = 0; break; case(3): LSA = 1; LSB = 1; LSC = 0; break; case(4): LSA = 0; LSB = 0; LSC = 1; break; case(5): LSA = 1; LSB = 0; LSC = 1; break; case(6): LSA = 0; LSB = 1; LSC = 1; break; case(7): LSA = 1; LSB = 1; LSC = 1; break; } P0 = dis_buf[i]; delay(100); P0 = 0x00; } } void key_scan() // 按键扫描 { if(K1 == 0) // K1按下 { delay(1000); if(K1 == 0) { key_value = 1; while(!K1); } } else if(K2 == 0) // K2按下 { delay(1000); if(K2 == 0) { key_value = 2; while(!K2); } } else if(K3 == 0) // K3按下 { delay(1000); if(K3 == 0) { key_value = 3; while(!K3); } } } void set_time() // 设置时间 { switch(set_pos) { case(0): // 设置小时 if(key_value == 1) // K1按下 { hour++; if(hour > 23) hour = 0; } else if(key_value == 2) // K2按下 { hour--; if(hour > 23) hour = 23; } break; case(1): // 设置分钟 if(key_value == 1) // K1按下 { min++; if(min > 59) min = 0; } else if(key_value == 2) // K2按下 { min--; if(min > 59) min = 59; } break; case(2): // 设置月份 if(key_value == 1) // K1按下 { month++; if(month > 12) month = 1; } else if(key_value == 2) // K2按下 { month--; if(month > 12) month = 12; } break; case(3): // 设置日期 if(key_value == 1) // K1按下 { day++; if(day > 31) day = 1; } else if(key_value == 2) // K2按下 { day--; if(day > 31) day = 31; } break; case(4): // 设置年份 if(key_value == 1) // K1按下 { year++; if(year > 99) year = 0; } else if(key_value == 2) // K2按下 { year--; if(year > 99) year = 99; } break; } } void set_alarm() // 设置闹钟 { if(key_value == 1) // K1按下 { alarm_hour++; if(alarm_hour > 23) alarm_hour = 0; } else if(key_value == 2) // K2按下 { alarm_min++; if(alarm_min > 59) alarm_min = 0; } } void main() { init_ds1307(); // 初始化DS1307 while(1) { key_scan(); // 按键扫描 if(mode == 0) // 时间模式 { sec = ds1307_read(0x00); // 读取秒 min = ds1307_read(0x01); // 读取分 hour = ds1307_read(0x02); // 读取时 display_time(); // 显示时间 if(key_value == 1) // K1按下,进入设置模式 { mode = 1; set_pos = 0; key_value = 0; } else if(key_value == 2) // K2按下,进入闹钟模式 { mode = 2; key_value = 0; } if(alarm_hour == hour && alarm_min == min) // 判断是否到达闹钟时间 { P1 = 0xff; // 发出警报 } else { P1 = 0x00; } } else if(mode == 1) // 设置模式 { set_time(); // 设置时间 display_time(); // 显示时间 if(key_value == 1) // K1按下,切换到下一个设置位置 { set_pos++; if(set_pos > 4) // 所有设置位置都设置完毕,退出设置模式 { mode = 0; ds1307_write(0x00, sec); // 写入秒 ds1307_write(0x01, min); // 写入分 ds1307_write(0x02, hour); // 写入时 ds1307_write(0x03, 0x01); // 星期一 ds1307_write(0x04, day); // 写入日 ds1307_write(0x05, month); // 写入月 ds1307_write(0x06, year); // 写入年 } key_value = 0; } else if(key_value == 2) // K2按下,退出设置模式 { mode = 0; key_value = 0; } } else if(mode == 2) // 闹钟模式 { set_alarm(); // 设置闹钟 P0 = table[alarm_hour / 10]; delay(100); P0 = table[alarm_hour % 10]; delay(100); P0 = 0x40; delay(100); P0 = table[alarm_min / 10]; delay(100); P0 = table[alarm_min % 10]; delay(100); P0 = 0x40; delay(100); if(key_value == 2) // K2按下,退出闹钟模式 { mode = 0; key_value = 0; } } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值