shell 脚本编程基础

Shell脚本简介:

Shell脚本是一种特殊的程序,它是用户与linux系统内核之间的一个接口,shell是一个工具程序,在用户登录后系统启动。它解释并运行由命令行或脚本文件输入的命令,从而实现用户与内核间的交互。

Shell脚本:也就是用各类命令预先放入到一个文件中,方便一次性执行的一个程序文件,主要是方便管理员进行设置或者管理用的,是利用shell的功能所写的一个程序,这个程序是使用纯文本文件,将一些shell的语法与指令写在里面,然后用正规表示法,管道命令以及数据流重导向等功能,以达到我们所想要的处理目的

 

程序:指令+ 数据

程序编程风格:

过程式:以指令为中心,数据服务于指令

对象式:以数据为中心,指令服务于数据

shell 程序:提供了编程能力,解释执行

程序的执行方式:

 计算机:运行二进制指令;

编程语言:

低级:汇编

高级:

编译:高级语言–> 编译器–> 目标代码

java,C#

解释:高级语言–> 解释器–> 机器代码

shell, perl, python

编程逻辑处理方式:

顺序执行

循环执行

选择执行

shell 编程:过程式、解释执行

编程语言的基本结构:

数据存储:变量、数组

表达式: a + b

语句:if

shell 脚本是包含一些命令或声明,并符合一定格式的文

本文件

格式要求:首行shebang 机制

#!/bin/bash

#!/usr/bin/python

#!/usr/bin/perl

shell 脚本的用途有:

         自动化常用命令

         执行系统管理和故障排除

         创建简单的应用程序

         处理文本或文件

创建shell脚本

    第一步:使用文本编辑器来创建文本文件

第一行必须包括shell 声明序列:#!(要顶格写)

#!/bin/bash

添加注释

注释以# 开头

第二步:运行脚本

给予执行权限,在命令行上指定脚本的绝对或相对路径

直接运行解释器,将脚本作为解释器程序的参数运行

可以是用:bash 脚本名称 

        这种用法是再打开一个子shell,在子shell中运行,不对当前环境改变

       source 脚本名称

       . 脚本名称

        source 和.一样,会对当前的环境改变

脚本的调试:

    bash -n /path/to/some_script

检测脚本中的语法错误

bash -x /path/to/some_script

调试执行

 

变量:

  变量:命名的内存空间

数据存储方式:

字符:

数值:整型,浮点型

  变量类型

作用:

1 、数据存储格式

2 、参与的运算

3 、表示的数据范围

类型:

字符

数值:整型、浮点型

编程程序语言分类:

   强类型:定义变量时必须指定类型、参与运算必须符合类型要求;调用未声明变量会产生错误

java,python

  弱类型:无须指定类型,默认均为字符型;参与运算会自动进行隐式类型转换;变量无须事先定义可直接调用

bash  不支持浮点数

变量命名法则:

1 、不能使程序中的保留字:例如if, for;

2 、只能使用数字、字母及下划线,且不能以数字开头

3 、见名知义

4 、统一命名Shell脚本包括一些命令或声明,并符合一个格式的文件

Bash中变量的种类

     根据变量的生效范围等标准:

本地变量:生效范围为当前shell 进程;对当前shell 之外的其它shell 进程,包括当前shell 的子shell 进程均无效

环境变量:生效范围为当前shell 进程及其子进程

局部变量:生效范围为当前shell 进程中某代码片断( 通常指函数)

位置变量:$1, $2, … 来表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数

特殊变量:$?, $0, $*, $@, $#

 本地变量:

变量赋值:name=value’,

可以使用引用value:

(1)  可以是直接字串; name=root"

(2)  变量引用:name="$USER"

(3)  命令引用:name=` COMMAND `, name =$(COMMAND)

变量引用:${name}, $name

"" :弱引用,其中的变量引用会被替换为变量值

'' :强引用,其中的变量引用不会被替换为变量值,而保

持原字符串

显示已定义的所有变量:set

删除变量:unset name

举例演示:

 1编写脚本/root/bin/systeminfo.sh.显示当前主机系统信息,包括主机名,IPv4地址,操作系统版本,内核版本,CPU型号,内存大小,硬盘大小。

脚本:

                                                 system脚本.png

 

  2、编写脚本/root/bin/backup.sh ,可实现每日将/etc/ 目录备份到/root/etcYYYY-mm-dd

脚本:

backup脚本.png

3、编写脚本/root/bin/disk.sh, 显示当前硬盘分区中空间利用率最大的值

 

disk.sh脚本.png

 

4、编写脚本/root/bin/links.sh, 显示正连接本主机的每个远程主机的IPv4 地址和连接数,并按连接数从大到小排序

脚本:

links.sh脚本.png

 

环境变量:

   变量声明、赋值:

export name=VALUE

declare -x name=VALUE

变量引用:$name, ${name}

显示所有环境变量命令:

export

env

printenv

删除:unset name

bash 有许多内建的环境变量:PATH, SHELL, USRE,UID,

        HISTSIZE, HOME, PWD, OLDPWD, HISTFILE, PS1

    

只读变量:

     只读变量:只能声明,但不能修改和删除

readonly name   

declare -r name      

位置变量

    位置变量:在脚本代码中调用通过命令行传递给脚本的参数

$1, $2, … :对应第1 、第2 等参数,shift [n] 换位置

$0:  命令本身

$*:  传递给脚本的所有参数,全部参数合为一个字符串

$@:  传递给脚本的所有参数,每个参数为独立字符串

$#:  传递给脚本的参数的个数

$@ $*  只在被双引号包起来的时候才会有差异(两者差异之处是,$*会把所有的参数当成一个整体;

     而$@会把所有参数分别对待;)

示例:判断给出的文件的行数

linecount="$(wc -l $1| cut -d' ' -f1)"

echo "$1 has $linecount lines."   

算术运算

        bash 中的算术运算:help let

+, -, *, /, % 取模(取余), ** (乘方)

实现算术运算:

(1) let var= 算术表达式

(2) var=$[ 算术表达式]

(3) var=$(( 算术表达式))

(4) var=$(expr arg1 arg2 arg3 …)

(5) declare i var =  数值

(6) echo 算术表达式’ | bc

(7) seq -s + 数值 数值 :计算两个数值之间的所有数的和

(8) scale 命令可以几位保留精度

  scale=2 表示保留两位精度(只对除法、取余、乘幂有效)

 例如:保留两位精度,echo "scale=2;111/22;" |bc  或者

              bc <<< "scale=2;111/22;"

乘法符号有些场景中需要转义 ,如 *

bash 有内建的随机数生成器:$RANDOM 1-32767

echo $[$RANDOM%50]  0-49

赋值

      增强型赋值:

+=, -=, *=, /=, %=

   let var OPER value

例如:let count+=3

自加3 后自赋值

自增,自减:

let var+=1  每次自加1

let var++  每次自加1

let var-=1  每次自减1

let var—  每次自减1

 

举例演示:

1 :写一个脚本/root/bin/sumid.sh ,计算/etc/passwd文件中的第10 个用户和第20 用户的ID 之和

脚本:

sumid.sh脚本.png

2 :写一个脚本/root/bin/sumspace.sh ,传递两个文件路径作为参数给脚本,计算这两个文件中所有空白行之和

脚本:

sumspace.sh脚本.png

3 :写一个脚本/root/bin/sumfile.sh, 统计/etc,  /var,  /usr目录共有多少个一极子目录和文件

脚本:

sumfile.sh脚本.png

逻辑运算

   true, false

1, 0

与:

1 1 = 1

1 0 = 0

0 1 = 0

0 0 = 0

:

1 1 = 1

1 0 = 1

0 1 = 1

0 0 = 0

       非:!

! 1 = 0

! 0 = 1

短路运算:

短路与:

第一个为0 ,结果必定为0

第一个为1 ,第二个必须要参与运算;

短路或

第一个为1 ,结果必定为1

第一个为0 ,第二个必须要参与运算;

异或:^

异或的两个值,相同为假,不同为真

 

        聚集命令

               有两种聚集命令的方法:

                 复合式:date; who | wc -l

命令会一个接一个地运行

                       shell (date; who | wc -l ) >>/tmp/trace

所有的输出都被发送给单个STDOUT STDERR

退出状态

         进程使用退出状态来报告成功或失败

 0 代表成功,1 255 代表失败

 $?  变量保存最近的命令退出状态

         例如:

$ ping -c1 -W1 hostdown &> /dev/null

$ echo $?

退出状态码

           bash 自定义退出状态码

exit [n] :自定义退出状态码;

注意:脚本中一旦遇到exit 命令,脚本会立即终止;终止退出

状态取决于exit 命令后面的数字

注意:如果未给脚本指定退出状态码,整个脚本的退出状态码

取决于脚本中执行的最后一条命令的状态码

条件测试

           判断某需求是否满足,需要由测试机制来实现;

专用的测试表达式需要由测试命令辅助完成测试过程;

评估布尔声明,以便用在条件性执行中

若真,则返回0

若假,则返回1

测试命令:

test EXPRESSIO

[ EXPRESSION ]

[[ EXPRESSION ]]

注意EXPRESSION前后必须有空白字符

条件性的执行操作符

        根据退出状态而定,命令可以有条件地运行

&&  代表条件性的AND THEN

|| 代表条件性的OR ELSE

Bash的测试类型

         数值测试:

-gt:  是否大于;

-ge:  是否大于等于;

-eq:  是否等于;

-ne:  是否不等于;

 

-lt:  是否小于;

-le:  是否小于等于

         字符串测试:

== :是否等于;

>: ascii 码是否大于ascii

<:  是否小于

!=:  是否不等于

=~:  左侧字符串是否能够被右侧的PATTERN 匹配

注意此表达式一般用于[[ ]] 中;

-z "STRING" :字符串是否为空,空为真,不空为假

-n "STRING" :字符串是否不空,不空为真,空为假 (要用双中括号‘[[]]’)

注意:用于字符串比较时的用到的操作数都应该使用引号

 

举例演示:

1 、写一个脚本/root/bin/argsum.sh ,接受一个文件路径作为参数;如果参数个数小于1 ,则提示用户“至少应该给一个参数”,并立即退出;如果参数个数不小于1 ,则显示第一参数所指向的文件中的空白行数

脚本:

argsum.sh脚本.png

 

2 、写一个脚本/root/bin/hostping.sh ,接受一个主机的IPv4 地址做为参数,测试是否可连通。如果能ping 通,则提示用户“该IP 地址可访问” ;如果不可ping 通,则提示用户“该IP 地址不可访问”

脚本:

hostping2.sh脚本.png

          文件测试

                 存在性测试

-a FILE :同-e

-e FILE:  文件存在性测试,存在为真,否则为假;

存在性及类别测试

-b FILE :是否存在且为块设备文件;

-c FILE :是否存在且为字符设备文件;

-d FILE :是否存在且为目录文件;

-f FILE :是否存在且为普通文件;

-h FILE -L FILE :存在且为符号链接文件;

-p FILE :是否存在且为命名管道文件;

-S FILE :是否存在且为套接字文件

                  文件权限测试:

-r FILE :是否存在且可读

-w FILE:  是否存在且可写

-x FILE:  是否存在且可执行

文件特殊权限测试:

-g FILE :是否存在且拥有sgid 权限;

-u FILE :是否存在且拥有suid 权限;

-k FILE :是否存在且拥有sticky 权限

                  文件大小测试:

-s FILE:  是否存 且非空;

文件是否打开:

-t fd: fd 表示文件描述符是否已经打开且与某终端相关

-N FILE :文件自动上一次被读取之后是否被修改过

-O FILE :当前有效用户是否为文件属主

-G FILE :当前有效用户是否为文件属组

                  双目测试:

FILE1 -ef FILE2: FILE1 FILE2 是否指向同一个设备上的相同inode

FILE1 -nt FILE2: FILE1 是否新于FILE2

FILE1 -ot FILE2: FILE1 是否旧于FILE2

组合测试条件

          第一种方式:

COMMAND1 && COMMAND2  并且

COMMAND1 || COMMAND2  或者

! COMMAND

如:[ -e FILE ] && [ -r FILE ]

第二种方式:

EXPRESSION1 -a EXPRESSION2  并且

EXPRESSION1 -o EXPRESSION2  或者

! EXPRESSION

必须使用测试命令进行

举例演示:

1 chmod -rw /tmp/file1 ,编写脚本/root/bin/per.sh,判断当前用户对/tmp/fiile1文件  是否不可读且不可写

脚本:

per2.sh脚本.png

 

2 、编写脚本/root/bin/nologin.sh login.sh, 实现禁止和允许普通用户登录系统

脚本:

 禁止登录:

nologin.sh脚本.png

 

允许登录:

login.sh脚本.png

 

使用read 来把输入值分配给一个或多个shell 变量:

-p 指定要显示的提示

-t TIMEOUT

read 从标准输入中读取值,给每个单词分配一个变量

所有剩余单词都被分配给最后一个变量

read -p “Enter a filename: “ FILE

流程控制

        过程式编程语言:

顺序执行

选择执行

循环执行

条件选择if语句

         选择执行:

注意 if 语句可 嵌套

单分支

if  判断条件:then

条件为真的分支代码

fi

双分支

if  判断条件; then

条件为真的分支代码

else

条件为假的分支代码

fi

           多分支

if  CONDITION1 ; then

if-true

elif CONDITION2 ; then

if-ture

elif CONDITION3 ; then

if-ture

else

all-false

fi

逐条 件进行判断,第一次遇为“真”条件时,执行其分支,而后 结束整个if 语句

条件判断:case语句

          case 变量引用 in

PAT1)

分支1

;;

PAT2)

分支2

;;

*)

默认分支

;;

esac

     case 支持glob 风格的通配符:

*:  任意长度任意字符

?:  任意单个字符

[] :指定范围内的任意单个字符

a|b: ab

举例演示:

1 、写一个脚本/root/bin/createuser.sh ,实现如下功能:使用一个用户名做为参数,如果指定参数的用户存在,就显示其存在,否则添加之;显示添加的用户的id 号等信息

脚本:

createuser.sh脚本.png

2 、写一个脚本/root/bin/yesorno.sh ,提示用户输入yes no, 并判断用户输入的是yes 还是no, 或是其它信息

脚本:

yesorno.sh脚本.png

3 、写一个脚本/root/bin/filetype.sh, 判断用户输入文件路径,显示其文件类型(普通,目录,链接,其它文件类型)

脚本:

filetype.sh脚本.png

4 、写一个脚本/root/bin/checkint.sh, 判断用户输入的参数是否为正整数

脚本:

checkint.sh脚本.png

5、判断硬盘的每个分区空间和inode的利用率是否大于80,如果是,发邮件通知root磁盘

脚本:

diskinode.sh脚本.png

 

6、指定文件做为参数,判断文件是否为.sh后缀,如果是,添加x权限

sh.sh脚本.png

7、判断输入的IP是否为合法IP

脚本:

iphefa.sh脚本.png

8、计算1+2+3+…+100

脚本:

1..100.sh脚本.png

9、输入起始值A和最后值B,计算从A+A+1…+(B-1)+B的总和

脚本:

A+B=.sh脚本.png

原创文章,作者:ZJM,如若转载,请注明出处:http://www.178linux.com/35902

(0)
ZJMZJM
上一篇 2016-08-21
下一篇 2016-08-21

相关推荐

  • linux第一周学习

      一周过去了,这周学习并新认识了不少内容。由一开始的萌逼状态,逐步清晰的认识了不少内容。相信我会越来越好的。 文件与目录 touch touch newfile         创建空文件touch oldfile          更新文件的三个…

    Linux干货 2017-09-02
  • 从Linux小白到大牛——与狼共舞的日子8

    马哥教育网络班21期+第8周课程练习 1、请描述网桥、集线器、二层交换机、三层交换机、路由器的功能、使用场景与区别。 网桥是第2层的设备,它设计用来创建两个或多个LAN分段。其中,每一个分段都是一个独立的冲突域。网桥设计用来产生更大可用宽带。它的目的是过滤LAN的通信流,使得本地的通信流保留在本地,而让那些定向到LAN其他部分(分段)的通信流转发到那里去。每…

    Linux干货 2016-11-14
  • 《 Git 权威指南 》学习笔记

    这个没办法直接发博客了,篇幅太长,无法直接在 Blog 上排版了,直接发上 pdf 文档了。 接 《LNAMP Shell 部署脚本》 博文的内容,线上测试系统的 Git 环境部署。 整个 Git 环境包括了:     Git / Gitweb     Gitolite / Gerrit &nbsp…

    Linux干货 2015-10-27
  • 相关练习

    1、请使用命令行展开功能来完成以下练习:    (1)、创建/tmp目录下的:a_c, a_d, b_c, b_d  mkdir /tmp/{a,b}_{c,d}    (2)、创建/tmp/mylinux目录下的:  mkdir -pv /tmp/mylinux/{bin,boot/grub,de…

    Linux干货 2016-11-05
  • 02Linux上终端的类型

    一、终端的概念 所谓终端就是在一个连接主机的端子上面接入鼠标、键盘、显示器等所组成的一个组合。终端用于用户与主机之间的交互。早期的时候,在大型主机上,想使用主机的用户很多,但是主机却只有一个,也不能实现人手一台。于是为了让一台主机给多个用户使用,便产生了多个终端和多个用户,这样每个用户只要有一个终端变可以与主机交互了。 二、终端的种类 终端的类型有四类:物理…

    Linux干货 2016-10-14
  • Linux计划任务

    Linux任务计划 Linux任务计划、周期性执行任务 未来某一时间点执行一次任务:at,batch 周期性计划任务:crontab     默认执行结果会通过邮件形式发送给用户 本地电子邮件服务 smtp:Simple Mail Transfer Protocol,既简单邮件传输协议,主…

    Linux干货 2016-09-14