2019年7月23日星期二(shell编程)
一. shell编程的理解?1. 什么是shell编程?shell编程通过shell语法写出来的文件,这个文件叫shell脚本。例如:Ubuntu中的“~/.bashrc”、开发板中的“/etc/profile”,shell编程有自身独特变量定义,循环结构,分支结构。 2. 怎么理解shell?shell在英文中翻译为"贝壳",在贝壳的内部叫内核,在贝壳的外部叫用户,用户与内核之间进行交互必须通过shell来进行解析。 例子: ?? 用户?????????????????????? shell??????????????????????????? 内核 ? 输入ls? ->? ls就是shell命令,使用shell命令解析进行解析?? ->? 通知内核打印当前目录下所有文件。 3. 如何解析命令?是谁在解析命令?1)解析命令必须有命令行,所以使用命令行之前必须打开一个linux终端,打开一个终端后,会自动运行一个bash进程。因为命令行"[email?protected]:~$"就是bash进程打印出来的。 2)其实就是bash进程在解析命令,也就是说没有命令行,命令是无效。 4. linux终端、bash进程、shell命令是什么关系?[email?protected]:~$ ps -ef? -> 查看当前系统中所有进程。 用户名?? 进程ID 父进程ID?????????????????????????? ??? 进程的名字 gec?????? 3950???? 1????? 0 18:26 ???????? 00:00:00 gnome-terminal?? -> linux终端 gec?????? 3956? 3950????? 0 18:26 pts/0??? 00:00:00 bash??? ???? -> bash进程,是linux终端的子进程 gec?????? 4024? 3956????? 0 18:30 pts/0??? 00:00:00 ps -ef? ???? -> shell命令,是bash进程的子进程 二. shell编程1. 什么是shell脚本?其实就是使用shell语法组织出来的一个文件,将来运行这个文件,就会依次执行里面每一行的shell语法,这个文件叫称之为shell脚本。 2. C语言程序与shell编程区别? ????????????? C语言程序????????????????? shell脚本文件 ==================================================================?????? 语法:????????? ? C语言???????????????????? ? shell语法 是否需要编译: 需要编译器编译??????????? 不需要编译,但是必须有解析器 文件后缀:?? ? xxxx.c??????????????? ? xxxx.sh 3. C语言程序与shell编程运行步骤对比:C语言:1. 创建文件? touch xxxx.c 2. 编辑程序? gedit xxxx.c 3. 编译程序? gcc xxxx.c -o xxxx 4. 执行程序? ./xxxx shell:1. 创建文件? touch xxxx.sh 2. 编辑脚本? gedit xxxx.sh 3. 修改脚本权限? chmod 777 xxxx.sh 4. 执行脚本? ./xxxx.sh 三. shell脚本helloworld程序。C语言:----------------------------- #include <stdio.h> ? int main() { ?????? printf("helloworld!n"); ?????? return 0; } ----------------------------- shell脚本:没有main函数,由于shell中不能调用函数,所以也不需要包含头文件,但是必须要指明一个东西,那么就是/bin/bash。 1. 怎么指明?shell脚本中第1行必须是:? #!/bin/bash?? -> 作用: 指明解析器的路径 2. shell中如何输出字符串到终端上?[email?protected]:/bin$ man 1 echo NAME? -> 对功能进行简单概括 echo - display a line of text? -> 显示文本 DESCRIPTION Echo the STRING(s) to standard output.? -> 将字符串输出到标准输出上。 -e???? enable interpretation of backslash escapes? -> 解析字符串上的转义符号? 例子: [email?protected]:/bin$ echo -e "hellon"?? -> 加了-e,就会解析n hello [email?protected]:/bin$ echo "hellon" hellon 综上所述,helloworld脚本应该是: shell脚本: -------------------------------- #!/bin/bash echo "helloworld" -------------------------------- 练习1:写一个脚本,要求输出以下的信息。 1. GZ1934<Tab键>guanguoyuan<Tab键>192.168.90.2 2. GZ1934 ?? guanguoyuan ?? 192.168.90.2 ? #!/bin/bash echo -e "GZ1934tguanguoyuant192.168.90.2" echo -e "GZ1934nguanguoyuann192.168.90.2" 四. shell脚本的变量定义。1. shell语法变量定义规则与C语言一致,只能使用下划线,数字,字母组成,并不能以数字开头。2. shell变量不需要声明数据类型,所有变量默认都是字符串类型C语言: int a /? char b shell: a? -> 默认就是字符串 3. shell语法中给变量赋值时,等号的两边不允许有空格C语言: int a = 100; /? int a=100;? --> OK Makefile:? CC = gcc? /? CC=gcc????? --> OK shell:? a=helloworld? -> OK??? a = helloworld? -> Error 4. shell语法对变量的引用,需要在变量前面添加$C语言: int a = 100; printf("%dn",a);?? -> 在C语言中引用变量不需要添加任何符号。 shell: a=helloworld echo $a 例子: #!/bin/bash str = hello?? -> 由于有空格,语法有误。但是不导致程序停止运行。 echo $str world ? 5. 变量种类。1)自定义变量? str=helloworld2)系统环境变量?? -> 通过shell命令"env"来查看。PWD=/mnt/hgfs/GZ1934/05 shell编程/01/code PATH=/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/arm/bin:/home/gec/project:/usr/arm/arm-2009q3/bin SHELL=/bin/bash 其中: PWD、PATH、SHELL就是系统的环境变量名字,自定义变量的名字不能与系统环境变量同名。 3)命令行变量?? -> 类似于C语言中argc与argvC语言:? ./hello aaa bbb argc = 3 argv[0] = "./hello" argv[1] = "aaa" argv[2] = "bbb" shell中也是可以传递参数: ./hello.sh aaa bbb $#:? 命令行额外(不算"./hello.sh"在内)的参数个数: $#=2 $1:? 第一个额外的参数:? $1=aaa $2:? 第二个额外的参数:? $2=bbb $*:? 代表所有的参数??? $*=aaa bbb $?:? 最后一条shell命令执行完的返回值??? shell命令执行成功:0? 执行失败:非0 练习2:写出命令行版helloworld脚本。 #!/bin/bash echo $1 结果: ./p2.sh helloworld 五. shell编程符号。1. 双引号?? -> 作用:将某些东西变成一个"值"1)字符串内部有空格时str=helloworld?? -> 正确 str="helloworld"? -> 正确 当双引号中字符串中没有空格时,加不加双引号。 str="hello world"? -> 正确 str=hello world?? -> 错误??? -> 如果有空格,必须添加双引号。 2)在""中能不能双引号变量?可以使用。 3)在""能不能用linux命令?可以使用,但是命令需要使用反引号(`)标识出来。 #!/bin/bash echo "today is date"?? -> 结果: today is date echo "today is `date`" -> 结果: today is Mon Jul 22 19:58:15 PDT 2019 2. 单引号?? -> 作用:把单引号括起来的内容看作是一个字符串。echo "today is `date`" -> 结果: today is Mon Jul 22 19:58:15 PDT 2019 echo ‘today is `date`‘ -> 结果: today is `date` 3. 反引号? ->? 作用:把双引号中的命令标识出来。echo "today is `date`" -> 结果: today is Mon Jul 22 19:58:15 PDT 2019 4. 重定位符号 > <六. 字符串处理1. 计算字符串的字符个数str=helloworld20helloworld30ashfadsghdcfytzvxcsdhfvtyasdvausd echo "${#str}" 2. 删除字符串左边/右边内容。常见shell通配符:? (通用的匹配符号)*: 代表任意长度的任意字符。 ?: 代表一个长度的任意字符。 [a-z]: 代表一个长度的a-z之间的字符 [az]: 代表一个长度,只能匹配a/z字符 [^az]: 代表一个长度,只能匹配除了a或者z之外的字符,与[az] #: 从左到右尽可能匹配少的字符 ##: 从左到右尽可能匹配多的字符 %: 从右到左尽可能匹配少的字符 %%: 从右到左尽可能匹配多的字符 删除字符串左边一些字符,例子: str=hello320abc20world echo "${str##*20}"?? -> 从左到右尽可能多地删除这种"*20"的东西?? -> 结果:world echo "${str##*[^ac]20}"?? -> 从左到右尽可能多地删除? 除了*a20/*c20? ->? 结果:abc20world echo "${str##*[ac]20}"?? -> 从左到右尽可能多地删除?? *a20/*c20?? 结果:world 删除字符串右边一些字符,例子: echo "${str%%20*}"? -> 结果: hello3 echo "${str%20*}"?? -> 结果: hello320abc 练习3: str=hello345abcsd3ffworldf45hello123world45hello 1. 计算字符个数 2. echo "${str##*3[a-z]}"??? orld45hello 3. echo "${str%3[a-z]*}"?? hello345abcsd3ffworldf45hello12 七.测试语句?1. 什么是测试语句?其实测试就是比较两个值的大小。类似C语言中"=="、"!="、strcmp() 2. 测试语句需要使用到test命令。? -> man 1 testNAME test - check file types and compare values? -> 测试文件类型以及比较值。 SYNOPSIS?? -> 使用格式 test EXPRESSION?? 等价于?? [ EXPRESSION ] DESCRIPTION? -> 详细参数描述。 INTEGER1 -eq INTEGER2 INTEGER1 is equal to INTEGER2 INTEGER1 -ne INTEGER2 INTEGER1 is not equal to INTEGER2 例子: 测试3是不是等于2 test 3 -eq 2?? 等价于?? [ 3 -eq 2 ] 八. 分支结构语句C语言分支:if-else? switch C语言循环:for while do-while shell分支:if-else? case shell循环:for while until 1. if-else分支框架: if 判定条件(测试语句) then ?????? xxxx elif 判定条件(测试语句) then ?????? yyyy else ?????? zzzz fi 2. 注意事项:1)测试语句的[]的两边不允许有空格。 2)每一个if语句都会fi作为结束标志。 3)if后面的判定条件为真(0)时,then后面的语句才会被执行。 4)else后面是没有then的。 ? 例题:判断命令行参数是不是为2个,如果不是2个就输出一个字符串报错。 ? #!/bin/bash if [ $# -ne 2 ] then ?????? echo "input arg error" fi ----------------------- #!/bin/bash if test $# -ne 2 then ?????? echo "input arg error" fi 练习4: 使用命令行传递文件名参数,例如: ./xxx.sh 1.txt,如果参数不等于1个,则输出字符串报错。判断该文件是否存在,如果存在,则在终端输出文件的内容,如果文件存在,但是没有读的权限,那么就添加读权限之后,再输出文件的内容,如果文件不存在,则输出字符串"file not exist"这个字符串来报错! #!/bin/bash if test $# -ne 1 then ?????? echo "input arg error" ?????? exit??? -> 直接退出程序 fi if [ -r $1 ] then ?????? cat $1 elif [ -e $1 ] then ?????? chmod 777 $1 ?????? cat $1 else ?????? echo "file not exist" fi 拓展: 使用C语言中完成这道题。 1. 在程序中如何直接退出程序?? ->? exit()? -> man 3 exit? ???? #include <stdlib.h> ??? void exit(int status); ?????? status: 退出时状态 ????????????? ?一般正常为0,异常为非0 ??? 返回值:无 例子: exit(0)? -> 直接正常退出程序 ????? exit(-1) -> 直接异常退出程序 2. 判断文件权限以及文件是否存在? -> access()? -> man 2 accessNAME access - check real user‘s permissions for a file? -> 判断文件权限,以及文件是否存在。 ???? #include <unistd.h> ?? int access(const char *pathname,int mode); ?????? pathname:需要判断的文件的路径 ?????? mode: F_OK? -> 判断文件是否存在 ?????? ?????? R_OK? -> 判断文件是否存在并可读 ?????? ?????? W_OK? -> 判断文件是否存在并可写 ?????? ?????? X_OK? -> 判断文件是否存在并可执行 ?????? 返回值: ????????????? 成功:存在,存在可读,存在可写,存在可执行? -> 0 ????????????? 失败:-1 3. 在C语言中如何执行linux命令?? ->? system()? -> man 3 systemNAME system - execute a shell command? -> 执行shell命令 ?????? #include <stdlib.h> ????? int system(const char *command);? ?????? command: 需要执行的linux命令 ?????? 返回值: ????????????? 成功:0 ????????????? 失败:-1 4. 拼接字符串? -> sprintf()? -> man 3 sprintf???? #include <stdio.h> ?? int sprintf(char *str,const char *format,...); ?????? str: 缓冲区地址 ?????? format: 格式 ?????? ...: 额外的参数 argv[1] = "1.txt" char buf[50] = {0}; printf("cat %s",argv[1]);? //将cat 1.txt打印在屏幕上 sprintf(buf,"cat %s",argv[1]);? //将"cat 1.txt"保存到buf数组中 参考: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <strings.h> int main(int argc,char *argv[])? //./p4 xxx { ?????? if(argc != 2) ?????? { ????????????? printf("input arg error!n"); ????????????? exit(-1); ?????? } ?????? ?????? char buf[50]; ?????? bzero(buf,50); ?????? if(access(argv[1],R_OK) == 0)? //存在并可读 ?????? { ????????????? sprintf(buf,argv[1]); ????????????? system(buf); ?????? } ?????? else if(access(argv[1],F_OK) == 0) //存在 ?????? { ????????????? sprintf(buf,"chmod 777 %s",argv[1]); ????????????? system(buf); ????????????? bzero(buf,50); ????????????? sprintf(buf,argv[1]); ????????????? system(buf); ?????? } ?????? else?? //不存在 ?????? { ????????????? printf("file not exist!n"); ?????? } ?????? ?????? return 0; } 2. case分支? -> 针对多种情况1)C语言中swtich语句框架switch(变量)? -> 整型,字符型,枚举类型 { ?????? case xx: ????????????? xxxx; ????????????? break; ?????? case yy: ????????????? yyyy; ????????????? break; ?????? default: ????????????? zzzz; ????????????? break; } 2)shell中case分支框架case 变量 in ?????? xx)?? xxxx;; ?????? yy)?? yyyy;; ?????? *)??? zzzz;; esac 拓展: C语言从键盘获取整型数据 int a; scanf("%d",&a); shell read a?? -> 阻塞从键盘中获取一个值,存放在a变量中 [email?protected]:/mnt/hgfs/GZ1934/05 shell编程/01/code$ read a hello [email?protected]:/mnt/hgfs/GZ1934/05 shell编程/01/code$ echo $a hello ? 练习5:执行程序后,从键盘中获取一个值,如果该值为1,则打印one,如果为10,就打印ten,如果都不是,则打印error #!/bin/bash read a case $a in ?????? 1)? echo "one";; ?????? 10) echo "ten";; ?????? *)? echo "error";; esac ? 练习6:假设有一个文件名字叫test.txt,内容为10,要求写一个脚本,判断文件的内容 ?????? ?内容为10,则打印large ?????? ?内容为5,则打印middle ?????? ?内容为1,则打印small ?????? ?其他值,则打印error ?????? ./test.sh test.txt? --> 要求判断传参问题。 #!/bin/bash if [ $# -ne 1 ] then ?????? echo "input arg error" ?????? exit fi val="`cat $1`" case $val in ?????? 10) echo "large";; ?????? 5)? echo "middle";; ?????? 1)? echo "small";; ?????? *)? echo "error";; esac 3. while循环1)框架: C语言: while(判定条件) {? //循环体 ?? ....? -> 循环内容 } ? shell: while 判定条件(测试语句) do? //循环体 ??? ....? -> 循环内容 done 2)shell中整型数据str? -> 默认是字符串类型 declare -i str?? -> str就是整型数据 ---------------------------------------- #!/bin/bash str=100 str=$str+1 echo $str? -> 结果: 100+1 --------------------------------------- #!/bin/bash declare -i str=100 str=$str+1 echo $str? ->结果: 101 ----------------------------------------- ? 练习7: 使用while循环打印1~100值。 #!/bin/bash declare -i n=1 while [ $n -le 100 ] do ?????? echo $n ?????? n=$n+1 done while循环的死循环: #!/bin/bash declare -i n=1 while [ $n -eq 1 ] do ?????? n=1 done (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |