作业6.21

【1】操作系统的结构

应用层:app/代码 通过shell和内核层交互 ---------------------------------------------- 内核层: 内核的五大功能: 1、文件管理 2、网络管理 3、进程管理 4、内存管理 5、设备管理 ---------------------------------------------- 硬件层:设备

【2】编程语言

编译型语言:C、C++ ----->通过编译,生成可执行程序再执行

解释型语言:shell、python ---->通过解释器

【3】第一个shell脚本

C语言是.c文件,shell脚本.sh文件,C++是.cpp后缀

#!/bin/bash #!/usr/bin/python ----->Ubuntu使用的python解析器 #shabang ---->#! #!表明脚本使用的解析器,在给脚本添加可执行权限后,直接脚本时生效 要求#!后面的解析器和脚本语言完全一致的 如果不写,默认匹配对应的解析器 echo "hello world" #shell终端指令 #表示注释 #第一个shell脚本

【4】运行脚本的三种方式

i)给文件添加可执行权限

chmod 0777 1.sh ./1.sh

ii)使用bash(常用)

不需要脚本有可执行权限

bash 1.sh 执行过程: 在后台打开一个新的终端,运行脚本,再将运行结果返回到当前终端

iii)source

不需要脚本有可执行权限

source 1.sh 执行过程: 在同一个终端完成运行和返回结果 source指令的格式: source filename ---->解读脚本,运行脚本中的指令 . filename ----->解读脚本,运行脚本中的指令 ./filename ---->添加了文件路径,运行可执行文件

【5】常见的shell解析器

  1. bash 与终端的交互性好,一般linux使用的都是bash
  2. sh 与终端的交互性较差,开发板的解析器常用的是sh

二、修改环境变量

在终端输入env查看系统提供的环境变量

【1】查看特殊的环境变量

echo $PATH

path是系统在执行指令时默认的查找路径

前面的a.out之所以不能够直接执行,需要加./,就是因为a.out的路径不在PATH检索的路径下。

【2】修改特殊的环境变量

就是把自己想添加的路径,追加到PATH中

i)只对当前终端生效的方式

export PATH= ${PATH}: /home/ubuntu/23041C/day2 | | | | 给环境变量赋值 赋值的变量 展开PATH 追加的内容

ii)只对当前用户生效的方式

修改家目录下的.bashrc文件,添加想要修改的路径

修改后让配置文件生效:

后两种都是临时生效的

  1. 重启(永久有效)
  2. source ~/.bashrc
  3. . ~/.bashrc

iii)对所有用户都生效的方式(常用)

修改/etc/bash.bashrc文件 在bash.bashrc的最后一行 ,使用exprot添加路径

修改后让配置文件生效: 改的是哪个文件,就运行哪个文件

  1. 重启
  2. source /etc/bash.bashrc
  3. . /etc/bash.bashrc

iv)对所有用户都生效的方式

修改/etc/environment文件 直接把路径添加到最后,以:作为分隔

修改后让配置文件生效: 改的是哪个文件,就运行哪个文件

  1. 重启
  2. source /etc/environment
  3. . /etc/environment

特殊的环境变量路径:只能对直接的子文件生效

三、变量

【1】复习

C语言中如何定义变量:

存储类型 数据类型 变量名; 存储类型: auto const static volatile register extern

【2】定义

shell是一个弱数据类型的语言,都是当作字符串处理的

shell脚本中定义变量时,等号两边不能有空格

变量名=变量的值 变量名='变量的值' 变量名="变量的值" #!/bin/bash #shell脚本就是指令的集合 var1=90 str='hello world' #''一般用于,变量的值中间有空格时 #''内不能识别$变量名,不会展开变量,只会当成字符串处理 str1="hello world" #使用已有的变量给新的变量赋值 str3="$str $str1" #""一般用于,使用一个变量给另一个变量拼接赋值 str4=$str3 echo $str3

【3】变量的访问

$变量名 ---->拿到变量的值 ${变量名} ---->正确表明变量名的范围,建议都加${} #!/bin/bash #shell脚本就是指令的集合 var1=90 str1='hello ' #echo $str1world #echo hello world ---->输出为hello world,空格被自动合并 #输出空行,把str1world识别为变量名 echo ${str1}world #${}的作用,正确识别变量的范围

【4】修饰变量的关键字

readonly:只读 unset:清空变量,不能清空readonly的变量 local:定义局部变量,只能在函数中时使用 shell脚本中,全部都是全局变量

作业

  1. 整理思维导图
  2. 重新写一遍变量部分的代码
  3. 课上的用户相关和磁盘相关操作再做一遍

练习:

1、将以下操作写在脚本中

在家目录下创建mydir目录,在mydir中创建dir1和dir2,

把/etc/passwd中的内容拷贝到dir1中,把/etc/group中的内容拷贝到dir2中,

把dir1压缩成xz格式,将压缩后的文件,拷贝到dir2中,把dir2中的内容解压,查看dir2中的内容。

#!/bin/bash cd ~ mkdir mydir mkdir mydir/dir1 mydir/dir2 cp /etc/passwd mydir/dir1 cp /etc/group mydir/dir2 tar -cJf mydir/dir1.tar.xz mydir/dir1 cp mydir/dir1.tar.xz mydir/dir2 rm mydir/dir1 -r tar -xvf mydir/dir2/dir1.tar.xz #---->会把mydir/dir1带路径的重新从mydir/dir2/dir1.tar.xz中解压缩出来 ls mydir/dir2 #--->dir1.tar.xz group 因为执行tar指令,源文件仍然存在

【5】外部传参/位置变量

$0 ---->脚本名 $1 ---->第一个参数 $2 ---->第二个参数 $3 ---->第三个参数 ··· $n ---->第n个参数 n>9 ${n} 获取外部参数的个数 $# ----->获取所有外部参数的个数,不包括脚本名 获取所有的外部参数 $@/$* ---->获取所有的外部参数,不包括脚本名

练习:

终端执行脚本名时,输入外部参数,输出第11个参数,并且再输出所有的参数,不包括脚本名

【6】输入/输出

i)echo

echo 要输出的内容 1、echo会自动换行 2、echo默认不解析转义字符 echo -n 取消换行 echo -e 解析转义字符

ii)read

read var ---->read后面直接跟变量名,如果read后面接多个变量,多个变量获取数据时以空格作为分隔 #如果没有多个变量,空格会作为字符串的一部分 read -p "提示信息" var #-p用于输出提示信息 read -s var #不回显终端的输入 read -t 4 var #如果4秒不输入,就结束输入 raed -n 3 var #输入三个字符就停止

思考

read的4个参数,可不可以一起使用?

#!/bin/bash read -p "请输入一个变量" -s -t 4 -n 3 var echo "----------------" echo $var #参数后面跟的内容,要和参数功能严格一致

【7】命令置换符

把指令运行的结果赋值给变量

  1. `` ---->反引号,~不按shift就是``
  2. $()

a=`ls` echo $a ---->就是ls的结果 a=$(ls) echo $a ---->就是ls的结果

练习:

1、用变量接收,Ubuntu在/etc/passwd中的行号,并打印。

#!/bin/bash line=`grep -n "^ubuntu" /etc/passwd | cut -d : -f 1 ` echo $line

四、shell中的数组

shell中只有一维数组,shell中支持稀疏数组,shell中支持变长数组

【1】定义

数组名=(初始值1 初始值2 初始值3 ····) arr=(12 34 56 hello) 数组名=([下标0]=初始值1 [下标2]=初始值2 [下标5]=初始值3 ····)

【2】访问数组中的元素

${arr[下标]} --->访问数组中具体的元素 ${arr[@]} ---->访问数组中的所有元素 ${arr[*]} ---->访问数组中的所有元素

【3】数组中元素的个数

${#arr[*]} ----->数组中元素的个数 ${#arr[@]} ----->数组中元素的个数 ${#arr[3]} ----->元素中字符的个数

shell中没有多维数组,只有一维数组数组

【4】使用已有的数组给新的数组赋值

#!/bin/bash arr=(12 566 hello) arr1=([0]=90 [5]=100 [7]=67) #稀疏数组,数组中的下标不连续 #echo ${arr1[7]} #arr[6]=78 #给arr数组中下标为6的元素赋值 #echo ${arr[6]} #echo "---------------" #echo ${#arr1[0]} #arr2和arr3的区别,在于元素个数的不同,因为arr2中两个数组链接时没有加空格 arr2=(${arr[*]}${arr1[@]}) arr3=(${arr[*]} ${arr1[@]}) echo ${arr2[2]} #hello90 echo ${arr3[2]} #hello

练习:

1、通过数组,计算家目录下文件个数

2、通过位置变量的方式给数组中元素赋值,并统计数组中元素个数

#!/bin/bash arr=(`ls ~`) #给数组赋值用()进行赋值 echo "家目录下文件的个数" ${#arr[*]} arr1=($*) echo "外部参数的个数" ${#arr1[@]}

五、shell中的算数运算

shell弱数据类型的

shell擅长执行指令,不擅长做运算

(()) $[] let expr

【1】使用(())进行算数运算

  1. (())常用于整形数据的运算
  2. (())支持大部分的C语言语法,并且支持C语言中的复杂语法
  3. (())支持幂运算,**
  4. (())使用变量可以加$也可以不加$,(())运算符两侧可以有空格也可以没有空格
  5. 使用var1=$((var1+var2)),接收(())运算的结果

#!/bin/bash var1=10 var2=90 #使用变量可以加$也可以不加$ #运算符两侧可以加空格,也可以不加空格 echo $((var1 +$var2)) ((var1=var1**3,var2++,++var2,var2=var1+var2)) #(())内,可以放多个表达式,每一个表达式都会执行,取最后一个的结果 echo $var2 #1092 echo $var1 #1000

练习:

1、终端输入两个数,求和并输出,再输出两数中的最大值

#!/bin/bash read var1 var2 ((sum=var1+var2)) echo $sum #echo $((var1+var2)) ((max=var1>var2?var1:var2)) echo $max

【2】$[]

  1. 格式:变量名=$[表达式1,表达式2,表达式3····],取最后一个表达式的结果,其余的也会运行
  2. $[]的运算结果,必须使用变量名接收
  3. 使用变量时,可以加$也可以不加
  4. 运算时,算数运算运算符两侧可以有空格也可以没有空格

#!/bin/bash var1=19 var2=80 sum=$[var1+ $var2] echo $sum

【3】let

  1. 格式:let 变量名=表达式,let和变量名中间一定要加空格
  2. 算术运算运算符两侧不能加空格
  3. 使用变量的值,可以加$也可以不加$
  4. let一定要放在,指令最前面

#!/bin/bash var1=19 var2=80 #sum=$[var1+ $var2] #let进行运算时,可以加$也可以不加,运算符两侧一定不能有空格 let sum=$var1+var2 echo $sum

【4】expr进行算术运算----->expr是一个指令

  1. expr 表达式
  2. 使用变量时必须加$
  3. 算术运算的运算符两侧一定要加空格
  4. expr不支持自增自减运算 、也不支持幂运算
  5. expr在使用时,需要对特殊字符转义,\. \* \> \
  6. expr执行的结果,结果会自动回显到终端,需要使用命令置换符获取给变量
  7. expr支持更多的运算

ARG1 | ARG2 若ARG1 的值不为0,则返回ARG1,否则返回ARG2,arg1不能为空 ARG1 & ARG2 若两边的值都不为0,则返回ARG1,否则返回 0 ARG1 < ARG2 ARG1 小于ARG2 ARG1 <= ARG2 ARG1 小于或等于ARG2 ARG1 = ARG2 ARG1 等于ARG2 ARG1 != ARG2 ARG1 不等于ARG2 ARG1 >= ARG2 ARG1 大于或等于ARG2 ARG1 > ARG2 ARG1 大于ARG2 ARG1 + ARG2 计算 ARG1 与ARG2 相加之和 ARG1 - ARG2 计算 ARG1 与ARG2 相减之差 ARG1 * ARG2 计算 ARG1 与ARG2 相乘之积 ARG1 / ARG2 计算 ARG1 与ARG2 相除之商 ARG1 % ARG2 计算 ARG1 与ARG2 相除之余数

expr中是否存在逻辑短路现象?不存在短路现象,因为在expr中只进行判断

expr支持的字符串运算

match STRING REGEXP 返回REG在STRING中,完全匹配的个数(从第一位开始匹配) substr STRING POS LENGTH 从string中pos下标的位置开始,截取长度为length的子串,下标从1开始 index STRING CHARS 返回多个字符中,最先在string出现的字符的位置 length STRING 求字符串的长度

练习:

1、终端输入一个文件名,截取出文件的扩展名。

如:1.sh 输出sh

2、终端输入网址www.hqyj.com

要求,截取出网址的每一个部分,放到数组中,并输出(不允许使用cut,也不能直接写下标)

例:

arr[0]=www

arr[1]=hqyj

arr[2]=com

#!/bin/bash read net pos1=`expr index $net '.'` #找第一个.的位置 str1=`expr substr $net 1 $((pos1-1))` len=`expr length $net` #求网址的长度 #新的字符串,不包括www.的字符串 temp=`expr substr $net $((pos1+1)) $len` pos2=`expr index $temp '.'` #找到新截取的子串中.的位置 str2=`expr substr $temp 1 $((pos2-1))` str3=`expr substr $temp $((pos2+1)) $len` arr=($str1 $str2 $str3) echo ${arr[0]} echo ${arr[1]} echo ${arr[2]}

六、shell中的分支结构

【1】if语句

在shell中,给大家的配置文件中可以自动补全if,补全的是[[]],平时写的是[]

[[]]和[]的区别

  1. []是test指令,[[]]只能被一些shell解析器识别
  2. []内使用逻辑于和逻辑或,需要用-a和-o参数,[[]]内可以直接使用|| &&
  3. []如果字符串不加"",可能不会正确识别字符串的范围,[[]]可以正确识别字符串范围

i)if单分支

//c中的 if(条件) { 条件成立执行的代码块; }

#shell中的格式 if [ 表达式 ] ------>if test 表达式 then 条件成立执行的命令 #有一个if就要有一个then中作为开始,有一个fi作为结束 fi

ii)if多分支语句

[] test指令

#shell中的格式 if [ 表达式1 ] ------>if test 表达式 then 条件成立执行的命令 #有一个if就要有一个then中作为开始,有一个fi作为结束 elif [ 表达式2 ] ----->test 表达式 then 表达式1不成立,但是表达式2从成立执行的语句块 else 表达式1不成立,并且表达式2也不成立执行的语句块 fi

【2】test指令

shell中test指令的作用,相当于c中的关系运算

使用test时,必须加空格

i)test处理数据时

-eq:相等 -ne:不相等 -ge:大于等于 -gt:大于 -le:小于等于 -lt:小于 -a:在test指令中表示逻辑与关系 -o:在test指令中表示逻辑或关系

练习:

1、终端输入年份,判断闰年还是平年(四年一闰、百年不闰,四百年再闰)

#!/bin/bash read year #在test内使用-a和-o判断,在test外面可以使用||和&& if [ $((year%4)) -eq 0 -a $((year%100)) -ne 0 ] || test $((year%400)) -eq 0 then echo "${year}是闰年" else echo "${year}是平年" fi

ii)test对于字符串的处理

如果test中遇到对字符串处理,必须加上""

-z string: 判断字符串为空 -n string: 判断字符串非空

iii)test对文件的操作

-b FILE:存在且为块设备文件 -c FILE:存在且为字符设备文件 -e FILE:文件存在 -f FILE:文件存在且为普通文件 -d FILE:文件存在且为目录文件 -s FILE:文件存在且不为空 -S FILE:文件存在且为套接字文件 -h/-L FILE:文件存在且为链接文件 -x FILE:文件是否有可执行权限

练习:

1、输入一个文件名,判断文件是否为普通文件,如果是普通文件,判断文件是否有可执行权限,如果有可执行权限,运行文件,如果没有可执行权限,就添加可执行权限。

#!/bin/bash read filename if [ -f $filename ] #判断是否为普通文件 then if [ -x $filename ] #判断是否有可执行权限 then ./$filename else chmod a+x $filename echo "添加可执行权限成功" fi fi

作业:

  1. 编写一个名为myfirstshell.sh的脚本,它包括以下内容。

1、包含一段注释,列出您的姓名、脚本的名称和编写这个脚本的目的 2、和当前用户说“hello 用户名” 3、显示您的机器名 hostname 4、显示上一级目录中的所有文件的列表 5、显示变量PATH和HOME的值 6、显示磁盘使用情况 7、用id命令打印出您的组ID 8、跟用户说“Good bye”

  1. 写一个shell脚本,获取当前用户名,用户id和工作路径
  2. 编写脚本,计算/etc/passwd文件中的第10个用户和第20用户的ID之和

输入学生成绩,判断等级

[100,90]A

(90,80]B

(80,70]C

(70,60]D

【3】case···in语句

C中的switch···case语句

switch 变量名 ----->是int或者是char,表达式也可以 { case 常量表达式: 语句块; break; default: 语句块; break; ··· case n: 语句块; } 例子: #include <stdio.h> int main(int argc, const char *argv[]) { int a = 98; switch (a) { case 10: printf("10\n"); break; default: printf("error\n"); break; case 98: printf("98\n"); } return 0; } 输出结果是98 switch···case中default的执行逻辑: 所有的case和default都是并列的关系, 当switch····case中所有的case都不满足时,才会去执行default,所以default的位置,不影响程序执行的效果。 如果不关心不满足case的其他情况,可以不写default

shell中的格式

case $变量名 in 表达式1) shell语句 ;; ------>相当于C语言中的break 表达式2) shell语句 ;; ···· *) ----->实现了C中default的作用 shell语句 ;; esac 表达式可以出现的情况: 1、*) 2、[1-2A-Z]) 3、1|2|3|4) 4、6) 例子: var=98 case $var in 10) echo 10 ;; *) #shell中*表示通配所有的情况,*只能写在最后 echo error ;; 98) echo 98 ;; #;;在shell中,只有在最后一个分支的情况下才能不写;; esac

case···in的注意事项

  1. *)会影响case···in语句的执行效果,如果想使用*)一定要放在最后
  2. case···in中的;;必须写出来,除了最后一条case情况

shell中的通配符

*:通配一个或多个字符 ?:通配一个字符 [1,2,3]:通配[]内的一个字符

练习:

  1. 输入学生成绩,判断等级

[100,90]A

(90,80]B

(80,70]C

(70,60]D

#!/bin/bash read score ((num=score/10)) case $score in 1??|9?) #通过按位或符号,实现case的多个选择 echo A ;; 8?) echo B ;; 7?) echo C ;; 6?) echo D ;; *) echo error esac

  1. 终端输入年和月份,判断该月有多少天,考虑闰平年的情况,平28,闰29

#!/bin/bash read year mon case $mon in 1|3|5|7|8|10|12) echo "31" ;; 4|6|9|11) echo "30" ;; 2) #shell脚本中,case和if也是可以嵌套的 if [ $(($year%4)) -eq 0 -a $(($year%100)) -ne 0 -o $(($year%400)) -eq 0 ] ; then echo "29" else echo 28 fi ;; *) echo error esac

  1. 终端输入字符,判断是数字还是标点,是大写字母还是小写子母

aAbBcCdD·····zZ ----->使用通配符,通配出来的字母序列

#!/bin/bash read c case $c in [0-9]) echo 是数字 ;; [[:upper:]]) echo 大写 ;; [[:lower:]]) echo 小写 ;; *) echo 符号 esac

  1. 终端输入游戏名,提示用户做出选择,如果用户选择Y|YES|y|yes就下载软件,如果用户选择N|NO|n|no就不下载软件。

read game read -p "是否下载软件" ch case $ch in Y|YES|y|yes) sudo apt-get install $game ;; N|NO|n|no) echo 不下载软件 esac

七、shell中的循环结构

【1】while循环

C语言中 while(条件) { 条件成立执行的代码块; 循环变量自增; }

shell中 while [ 表达式 ] ----->while test 表达式 do 表达式成立执行的指令 done

练习:

1、求1-100的和

#!/bin/bash i=1 sum=0 while [ $i -le 100 ] #使用le参数才能,让100进入循环 do ((sum+=i)) ((i++)) done echo $sum

2、终端输入行数,打印直角三角形

*

**

***

····

#!/bin/bash read -p "请输入行数" line i=1 j=1 while [ $i -le $line ] do j=1 #每行打印时j都从1开始 while [ $j -le $i ] do echo -n "*" ((j++)) done echo "" ((i++)) done

3、使用while循环,求数组中元素的和

#!/bin/bash arr=(1 2 3 4) i=0 sum=0 num=${#arr[*]} while [ $i -lt $num ] do ((sum+=${arr[$i]})) #每次加上数组中的元素,${arr[下标]} ((i++)) done

4、写一个99乘法表(printf "%d*%d=%d\n" $a $b $((a*b)))

【2】for循环

for循环在shell中主要有两种格式

i)类似于C的格式

C中的格式 for(表达式1;条件;自增语句) { } shell中类似C的for格式 for ((表达式1;条件;自增语句)) do 循环体 done

ii)shell中的写法

for 变量名 in 字符串列表 do 循环体 done 执行逻辑: 字符串列表中的是变量可能出现的所有情况,for循环执行的次数和字符串的个数有关, 变量要顺序遍历结果字符串列表中的每一种情况,for循环才结束。

练习:

1、求1-100的和

2、使用for循环,求数组中元素的和

#!/bin/bash arr=([0]=1 [4]=2 [7]=3 [9]=4 [10]=8) sum=0 #for i in 1 2 3 4 8 for i in ${arr[*]} do ((sum+=i)) done echo $sum

iii)for后面跟连续列表的情况

1、seq指令用于输出连续序列 格式: seq 起始值 间隔值 终止值 起始值和间隔值都可以省略,如果省略,默认为1 2、{1..100} 只能用在for循环中in的后面,表示从1-100的连续序列 中间只能是..

练习:

1、使用循环,求出家目录下,普通文件的个数,目录文件的个数。

#!/bin/bash countfile=0 countdir=0 #i在循环中,会遍历家目录下每个文件名 for i in `ls ~` do if [ -f ~/$i ] #判断文件是否是普通文件 需要给文件加上目录 then ((countfile++)) elif [ -d ~/$i ] #判断文件是否是目录文件 then ((countdir++)) fi done echo "普通文件个数$countfile" echo "目录文件个数$countdir"

2、求外部参数的和

#!/bin/bash sum=0 for i in $* do ((sum+=i)) done echo $sum

【3】select···in语句

i)格式

select 变量名 in 选项列表 do 循环体 done 执行逻辑: select···in语句会列出选项列表,#?提示用户选择,如果用户不选择,再提示一次选项列表 选择时,选的是编号不是具体的内容,ctrl+c结果 例子: #!/bin/bash select i in aa bb cc dd do echo $i done 运行结果: 1) aa 2) bb 3) cc 4) dd #?

ii)与case···in结合使用

select···in和case···in结合使用,可以实现根据选择不同执行不同的指令

#!/bin/bash select i in linux wins unix do case $i in linux) echo "打开的是ubuntu系统" ;; wins) echo "打开的是wins系统" ;; unix) echo "打开的是unix系统" esac done

【4】辅助控制关键字

break/continue

i)break

跳出本层循环

break n 跳出n层循环,如果n=1可以不写

ii)continue

跳出本次循环

continue n 跳出n层本次循环,如果n=1可以不写

#!/bin/bash for ((i=0;i<3;i++)) do echo "第一层循环 i=$i----------------------------" for((j=0;j<3;j++)) do echo "第二层循环 j=$j--------------------------" for((k=0;k<4;k++)) do echo "第三层循环 k=$k------------------------" if [ $k -eq 2 ] then echo "准备结束本层循环" #break 3 continue 3 fi echo "第三层循环" done echo "第二层循环" done echo "第一层循环" done

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值