shell编程

一、学习shell编程有什么用》

1.对shell编程的理解

 shell编程就是通过shell这种新语法写出来的一个文件,这个文件称之为shell脚本。

shell脚本一般不是由开发工程师去写的,都是由运维工程师去完成,所以我们只需要懂得里面的语法就可以了。

在 linux下有一些已经写好的shell脚本 ,

ubuntu下的家目录下   :   .bashrc   -》每当一个用户开启一个新的终端时,就会执行这个脚本

开发板下的etc目录:          profile    -》每当开发板启动时,就会默认执行这个脚本

 

2、在linux下,如何解析命令?是谁在解析命令?

1)怎么理解shell? shell在英文中被翻译为"贝壳",贝壳里面的是珍珠,贝壳外面是用户,用户想访问珍珠,必须要通过贝壳才可以访问。

例子:

用户输入 shell解析器 内核

ls ----> ls是命令,所以需要系统来解析 ---> 将这个解析的结果传输给内核,内核就会列出所有的文件名

2)究竟shell解析器是谁?

gec@ubuntu:~$ ps -ef

   PID号   父进程PID号

gec 2562 1626 0 May09 ? 00:00:50

/usr/lib/gnome-terminal/gnome-terminal-server --> 终端

gec 2569 2562 0 May09 pts/4 00:00:00 bash --> bash进程

gec 7934 2569 0 00:30 pts/4 00:00:00 ps -ef --> 命令

-------------------Terminal(终端)-------------------- -gec

@ubuntu:~$(bash进程)

ps -ef(命令) -

  •  


结论:

1)bash进程就是命令行。 所有的命令都是写在命令行上,没有命令行,命令就是无效,因为没有命令行去解析该命令。 shell解析器其实指的是命令行(因为命令行是专门用来解析命令的)。

2)为什么命令行叫bash进程? 因为命令行就是bash程序执行的结果。 因为在启动一个终端时,系统默认执行bash程序,而执行这个bash程序,就会在终端上产生一个命令。

3)把整个逻辑理清。

打开一个终端 --> 默认执行bash程序 -> 产生一个命令行(shell解析器) --> 命令写在命令行的后面 bash是终端的子进程 bash就是命令行 命令是命令行(bash)的子进程

4)bash进程在哪里?

gec@ubuntu:~$ which bash /bin/bash -> 当开启一个终端时,就会默认执行这个程序,而"gec@ubuntu:~$"就是这个程序的结果。

二、shell编程。

1、什么是shell编程? 现在我们知道命令是由命令行来解析的,我们现在将一些命令写到一个文件中,然后执行这个文件,那么shell解析器就会依次帮我们去执行里面的命令。

2、C语言程序与shell脚本有什么区别?

C语言程序 shell脚本

语法: C语言  shell语法

是否需要编译: 需要编译 不需要编译

文件后缀: xxxx.c xxxx.sh 编辑环境: linux/windows linux (因为在windows中编辑,可能会有问题)

3、C语言程序与shell脚本运行步骤?

C语言程序:

1)创建文件: touch xxx.c

2)编辑文件: gedit xxx.c

3)编译文件: gcc xxx.c -o xxx (因为gcc编译出来的文件默认是有执行权,所以不用再添加了)

4)执行文件: ./xxx

shell脚本:

1)创建文件: touch xxx.sh (因为新创建的文件是没有执行权)

2)编辑文件: gedit xxx.sh

3)添加执行权限: chmod 777 xxx.sh

4)执行脚本: ./xxx.sh

三、shell脚本中helloworld程序。 shell脚本中没有main函数,不能调用C语言函数,所以不需要包含头文件,但是一定要指明一个内容:解析器的路径。

1、怎么指明解析器? 只需要在shell脚本中的第一行写上: #!/bin/bash

2、如何输出字符串到终端上? --> echo命令 -> man 1 echo

功能: echo - display a line of text //显示一行文本到终端

使用格式:

echo [SHORT-OPTION]... [STRING]... echo [参数]... [字符串]...

参数:

-n          do not output the trailing newline //不会在输出字符串之后提供换行

-e           enable interpretation of backslash escapes //解析字符串上的转义字符

gec@ubuntu:~$ echo -n hello

hellogec@ubuntu:~$

gec@ubuntu:~$ echo "hello\n"

hello\n

gec@ubuntu:~$ echo -e "hello\n"

hello                   --> 解析了\n得到一个换行

                           --> 默认再给一个换行 gec@ubuntu:~$

3、写程序。
1)在linux下创建一个工程文件。 touch hello.sh

echo helloworld

3)由于在共享目录下,已经默认有执行权限了,那么不需要再给了 如果在别的目录下,就需要手动添加。chmod 0777 ./hello.sh

4)执行文件。 ./hello.sh

#!/bin/bash

echo -e "GZ2119\tguanguoyuan\t192.168.19.3"
echo -e "GZ2119\nguanguoyuan\n192.168.19.3"

四、shell脚本中变量的定义。

1、shell语法变量中定义变量规则与C语言一致,只能使用数字、字母,下划线组成,不能用数字开头。

2、shell变量不需要声明数据类型,因为变量默认都是字符串类型。

C语言: int a / char b

shell: a / b -> 默认就是字符串类型

3、shell语法中对变量赋值时,等号两边不允许有空格。

C语言: int a = 100 -> 正确

               int a=100 -> 正确

shell: a=hello -> 正确

            a = hello -> 错误

4、shell语法中对变量的引用,需要在变量的前面添加$

C语言:

int a = 100;

printf("%d\n",a);       -> 在C语言中引用变量不需要添加任何符号。

shell:

a=helloworld

echo $a               -> 在shell中需要使用$来引用变量。

5、变量的种类。

1)自定义变量 -> str=hello (str就是自定义变量)

2)系统环境变量 -> 通过shell命令env来查看 (PATH就是环境变量) PATH=/home/gec/bin:/home/gec/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/arm/5.4.0/usr/bin

3)命令行变量 -> 类似于C语言的argc与argv

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

#!/bin/bash 
echo $#
echo $1
echo $2
echo $*
echo $?

 

五、shell编程符号。

1、双引号

作用:将某一块东西变成一个值。

1)空格问题。

当一个字符串中没有空格时

echo helloworld --> 正确

echo "helloworld" --> 正确 加不加双引号都无所谓

当一个字符串中有空格时

str=hello world --> 错误

str="hello world" --> 正确 必须要添加""

2)在""中引用变量? 可以。

#!/bin/bash

a=world

str="hello $a"

echo $str

3)可不可以在""中使用一些Linux命令?

echo "today is date" -> 结果: today is date

echo "today is date" -> 结果: today is Mon May 10 02:15:54 PDT 2021

echo 'today is date' -> 结果: today is date

2、单引号。

作用: 将单引号括起来的内容看做是一个字符串。

3、反引号。

作用: 把双引号中的命令标识出来。

六、字符串处理。

1、计算字符串中字符的个数。

str=ashdvasvdahsvdhasvbdasbdfysvdytfbsdfuyvstdfartsvd

echo "${#str}" -> 49

2、删除字符串左边/右边的内容。

常见shell通配符:(通用匹配符号)

*: 代表任意长度的任意字符。

?: 代表一个长度的任意字符。

[a-z]  代表一个长度的a-z之间的字符。 

[az]  代表一个长度、只能匹配a/z字符。 

[az]  代表一个长度、只能匹配除了a/z的字符。

#: 从左到右尽可能匹配少的字符。

##: 从左到右尽可能匹配多的字符。

%: 从右到左尽可能匹配少的字符。

%%: 从右到左尽可能匹配多的字符。

1)删除字符串左边的字符,

例如: str=hello320abc20world

echo "${str#20}" --> 从左到右尽可能少地去删除"20"这种东西。 --> 结果: abc20world

echo "${str##20}" --> 从左到右尽可能多地去删除"20"这种东西。 --> 结果: world

echo "${str##[ac]20}" --> 从左到右尽可能多地去删除"[ac]20"这种东西。 --> 结果: world

                                                                                   a20/c20

echo "${str##[^ac]20}" --> 从左到右尽可能多地去删除"ac20"这种东西。--> 结果: abc20world

                                                                                                                    *(一个不是a/c的字符)20

2)删除字符串右边的一些字符,

例如:

str=hello320abc20world

echo "${str%%20}" --> 从右到左尽可能多地去删除20这种东西 --> 结果: hello3

echo "${str%20}" --> 从右到左尽可能少地去删除20这种东西 --> 结果: hello320abc

 

七、测试语句。 1、什么是测试语句? 其实测试语句就是可以比较两个值(整型数据/字符串)是否相等/大于/小于/一致。 类似于C语言中的== != > >=

2、测试语句需要使用一个命令。 --> test -> man 1 test 功能: test - check file types and compare values //检查文件类型以及比较一些值

使用格式: test EXPRESSION 等价于 [ EXPRESSION ] test 判断表达式 等价于 [ 判断表达式 ]

判断表达式有以下这些:

STRING1 = STRING2                     the strings are equal //判断两个字符串是否相等

STRING1 != STRING2                   the strings are not equal //判断两个字符串是否不相等

INTEGER1 -eq INTEGER2            INTEGER1 is equal to INTEGER2 //判断两个整型数据是否相等

INTEGER1 -ge INTEGER2              INTEGER1 is greater than or equal to INTEGER2 //判断第一个整型数据是否大于/等于第二个整型数据

INTEGER1 -gt INTEGER2 INTEGER1 is greater than INTEGER2 //判断第一个整型数据是否大于第二个整型数据

INTEGER1 -le INTEGER2 INTEGER1 is less than or equal to INTEGER2 //判断第一个整型数据是否小于/等于第二个整型数据

INTEGER1 -lt INTEGER2 INTEGER1 is less than INTEGER2 //判断第一个整型数据是否小于第二个整型数据

INTEGER1 -ne INTEGER2 INTEGER1 is not equal to INTEGER2 //判断第一个整型数据是否不等于第二个整型数据

-e FILE FILE exists //判断文件是否存在

-r FILE FILE exists and read permission is granted //判断文件是否存在,并且可读。

-w FILE FILE exists and write permission is granted //判断文件是否存在,并且可写。

-x FILE FILE exists and execute (or search) permission is granted //判断文件是否存在,并且可执行。

 

八、分支语句。 -- if-else分支

C语言: if-else分支 switch分支

shell: if-else分支 case分支

1、shell中if-else分支的框架。

框架:

if 判定条件1(测试语句)

then

xxxx

elif 判定条件2(测试语句)

then yyyy

else -> 既不满足条件1,也不满足条件2

zzzz

fi

2、例题: 判断命令行额外的参数是不是为2个,如果不是2个,则输出一个字符串来报错。

$#


#!/bin/bash

if test $# -ne 2

then

echo "input arg error!"

fi

 

#!/bin/bash

if [ $# -ne 2 ]

then

echo "input arg error!"

fi


3、注意事项。

1)测试语句[]两边都必须有空格。

2)每一个if语句都会以fi作为结束标志。

3)if后面的判断条件必须是真(0)时,then后面的语句才会被执行。

4)else后面没有then。

 

练习5: 使用命令行来传递文件名,例如:./xxx.sh 1.txt,如果额外的参数不等于1个,则输出字符串来报错。判断该文件是否存在并可读,如果存在并且可读,那么在终端上 输出文件的内容。如果只是存在,但是不可读,那么就添加读的权限之后,再输出文件的内容,如果文件不存在,则输出"file not exists"这个字符串来报错。

1)请使用shell编程来完成这个题目。

#!/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 exists"

fi
   2)请使用C语言来完成这个题目。
#include "head.h"

int main(int argc, char *argv[]) // ./p5 1.txt

{

    if (argc != 2)
    {
        printf("input arg error!\n");
        exit(-1);
    }

    char buf[100];
    bzero(buf, sizeof(buf));
    ​ 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, sizeof(buf));
        sprintf(buf, "cat %s", argv[1]);
        system(buf);
    }
    else
    {
        printf("file not exists!\n");
    }
    ​ return 0;
}

 

九、分支结构 -- case分支。

1、case分支框架。

C语言swtich分支框架:

swtich(变量) {

case x: xxxx; break;

case y: yyyy; break;

default: zzzz; break;

}

shell中case分支框架:

case $变量 in

x) xxxx;;

y) yyyy;;

*) zzzz;;

esac

2、拓展: 从键盘中获取数据。

C语言:

char A[10];

scanf("%s",A);

shell:

read a -> 阻塞从键盘中获取内容,然后存放在变量a中。

3、例题: 执行程序后,从键盘中获取一个值,如果该值为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。
​
1)请使用shell编程来完成这个题目。
#!/bin/bash
val="`cat $1`"
case $val in
    10) echo "large";;
    5) echo "mid";;
    1) echo "small";;
    *) echo "error";;
esac

十、循环结构。 -- while循环。

C语言:for循环、while循环、do-while循环。

shell:for循环、while循环、until循环。

1、while循环的框架。

C语言:

while(判定条件) { //循环体 ...; }

 

shell语言:

while 判定条件(测试语句)

do

//循环体 ....

done

2、在shell中处理整型数据。

str -> 默认是字符串类型。

#!/bin/bash

str=100

str=$str+1

echo $str

结果:100+1

declare -i str=100 -> 指定str是整数。

#!/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
练习8: 研究while循环的死循环怎么写?
#!/bin/bash

declare -i n=1

while [ $n -eq 1 ]

do

n=1

done

十一、循环结构 --- until循环。

until循环与while循环非常相似。

while循环 -> 当xxx条件成立时,就做循环体的内容,当xxx条件不成立时,就不做循环体的内容。

until循环 -> 当xxx条件不成立时,就做循环体的内容,当xxx条件成立时,就不做循环体的内容。

until循环框架:

until 判定条件(测试语句)

do

//循环体 ....

done

练习9: 使用until循环打印1~100的值。

#!/bin/bash

declare -i n=1

until [ $n -gt 100 ]

do

echo $n

n=$n+1

done

练习10: 研究until循环的死循环。

#!/bin/bash

declare -i n=1

until [ $n -gt 100 ]

do

n=1

done

十二、循环结构 --> for循环

1、for循环框架。

for 变量 in 内容(使用空格分开)

do

//循环体

done

2、举例子。

#!/bin/bash

str="hello world apple tree"

for n in $str //每次循环,n就去str中取一个值。

do

echo $n

done

运行结果: gec@ubuntu:/mnt/hgfs/GZ2119/05 shell编程/code$ ./for.sh

hello

world

apple

tree

十三、shell函数。

1、在shell中,函数与C语言函数非常相似,都是用于封装内容,但是使用方式要比C语言更加简单。 C语言例子:

int fun(char *p1,char *p2) -> 形式参数

{

printf("p1 = %s\n",p1); //hello -> 调用形式参数

printf("p2 = %s\n",p2); //world

return 10; -> 使用return语句来返回一个值

}

int main(int argc,char *argv[])

{ i

nt ret;

ret = fun("hello","world");

printf("ret = %d\n",ret); //10

return 0;

}

 

2、shell的函数是怎么写的? 1)shell中函数形式参数怎么写?如何调用形式参数?以及返回值给调用的地方?

fun() -> 在括号中不需要写任何的东西

{

-> 函数体

-> $1 -> 第一个形式参数

-> $2 -> 第二个形式参数

-> $* -> 所有的形式参数

return 10    -> shell也是使用return来返回函数的返回值

}

2)如何调用函数?

fun hello world -> 可以理解为等价于执行了一条命令。

3)查看返回值?

只需要在函数调用之后,查看$?的值就可以了。

3、 使用shell编程来完成上述的代码。

#!/bin/bash

fun() {

for s in $*

do

echo $s

done

return 10

}

fun hello world

echo $?

注意: 什么时候$1是命令行的第一个参数,什么时候是第一个形式参数?

fun() {

$1 -> 第一个形式参数

$2 -> 第二个形式参数

$* -> 所有的形式参数

}

$1 -> 命令行第一个额外的参数

$2 -> 命令行第二个额外的参数

$* -> 命令行所有额外的参数

十四、trap命令。 --> man 1 trap

功能: trap — trap signals

捕捉信号

例题: 假设某一个正在运行的脚本收到SIGINT信号时,就执行一个函数。

#!/bin/bash

fun() {

echo "helloworld"

return 0;

}

trap fun SIGINT

declare -i n=0

while [ $n -eq 0 ]

do

n=0

done

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值