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进程。因为命令行"gec@ubuntu:~$"就是bash进程打印出来的。

2)其实就是bash进程在解析命令,也就是说没有命令行,命令是无效。

4. linux终端、bash进程、shell命令是什么关系?

gec@ubuntu:~$ 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中如何输出字符串到终端上?

gec@ubuntu:/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  -> 解析字符串上的转义符号  \

例子:

gec@ubuntu:/bin$ echo -e "hello\n"   -> 加了-e,就会解析\n

hello

gec@ubuntu:/bin$ echo "hello\n"

hello\n

综上所述,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 "GZ1934\tguanguoyuan\t192.168.90.2"

echo -e "GZ1934\nguanguoyuan\n192.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("%d\n",a);   -> 在C语言中引用变量不需要添加任何符号。

shell:

a=helloworld

echo $a

例子:

#!/bin/bash

str = hello   -> 由于有空格,语法有误。但是不导致程序停止运行。

echo $str world

 

5. 变量种类。

1)自定义变量  str=helloworld

2)系统环境变量   -> 通过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语言中argcargv

C语言:  ./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 test

NAME

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 access

NAME

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 system

NAME

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,"cat %s",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,"cat %s",argv[1]);

              system(buf);

       }

       else   //不存在

       {

              printf("file not exist!\n");

       }

      

       return 0;

}

2. case分支  -> 针对多种情况

1C语言中swtich语句框架

switch(变量)  -> 整型,字符型,枚举类型

{

       case xx:

              xxxx;

              break;

       case yy:

              yyyy;

              break;

       default:

              zzzz;

              break;

}

2shellcase分支框架

case 变量 in

       xx)   xxxx;;

       yy)   yyyy;;

       *)    zzzz;;

esac

拓展:

C语言从键盘获取整型数据

int a;

scanf("%d",&a);

shell

read a   -> 阻塞从键盘中获取一个值,存放在a变量中

gec@ubuntu:/mnt/hgfs/GZ1934/05 shell编程/01/code$ read a

hello

gec@ubuntu:/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

2shell中整型数据

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

猜你喜欢

转载自www.cnblogs.com/zjlbk/p/11233758.html
今日推荐