linux之基础shell脚本编程1 基础变量赋值

本章主要介绍函数的基础,变量赋值,逻辑运算,条件表达式,测试

linux之基础shell脚本编程1  基础变量赋值

linux之基础shell脚本编程2 if语句循环判断

linux之基础shell脚本编程3 函数数组

linux之基础shell脚本编程4 字符串操作,变量赋值,配置用户环境 
 

一,编程基础的介绍

1.1 编程基础

程序是由指令和数据组成的

程序编程风格可分为面向对象和面向过程编程

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

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

sehll程序提供了编程能力,是通过解释器解释执行的

1.2 程序的执行方式

计算机只能运行二进制指令;

编程语言:

         低级:汇编

         高级:

                   编译:高级语言 --> 编译器 --> 目标代码  比如 java,C# 等

                   解释:高级语言 --> 解释器 --> 机器代码  比如 shell perl python 等

1.3 编程基本概念

编程逻辑处理方式:

  • 顺序执行
  • 循环执行
  • 选择执行

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

  编程语言的基本结构:

    数据存储:变量,数组 等

    表达式:a+b 等

    语句:if while 等

二,shell脚本编程

2.1 shell脚本基础

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

格式要求:首行shebang机制

  #!/bin/bash

  #!/usr/bin/python

  #!/usr/bin/perl

shell脚本的用途:

  • 自动化常用命令
  • 执行系统管理和故障排除
  • 创建简单的应用程序
  • 处理文本或文件

2.2 创建shell脚本

第一步:使用文本编辑器来创建一个以 .sh 为结尾的文本文件,第一行必须包括shell声明序列:#!/bin/bash ;添加适当的注释,注释以 # 开头

第二步:运行脚本,首先,先给脚本赋予执行权限,在命令行上指定脚本的绝对或相对路径;也可以直接运行解释器,将脚本作为解释器程序的参数运行

脚本范例如下:

#!/bin/bash
#author: nineven
#Version: 1.0
#Description:This script displays some information about your
# environment 

echo "Greetings. The date and time are $(date)" echo "Your working directory is: $(pwd)"
 

2.3 脚本调试

 bash -n /path/to/some_script  #检查脚本中的语法错误(这个功能好像不怎么好用)
bash -x /path/to/some_script  #调试执行,感觉很强大

2.4 编程程序语言分类

强类型:

        定义变量时必须指定类型,参与运算必须符合类型要求,调用未声明变量会产生错误,比如 java python

弱类型:

        无须指定类型,默认均为字符型,参与运算会自动进行隐式类型转换,变量无须事先定义可直接调用,比如 bash 不支持浮点数

变量命令法则:

  •  不能使用程序中的保留字:比如 if for 等
  •  只能使用数字,字母及下划线,且不能以数字开头
  •  见名知义

2.5 变量

变量:命名空间的内存空间

变量的数据存储方式:

         字符

         数值,比如 整形,浮点型

变量的类型:

         字符

         数值:整形,浮点型

变量的作用:

  •  数据存储格式
  •  参与的运算
  •  表示的数据范围

2.5.2 bash中的变量的种类

根据变量的生效范围等标准可分为以下几类:

  •  本地变量:生效范围为当前shell进程,对当前shell之外的其他shell进程,包括当前shell的子shell进程均无效
  •  环境变量:生效范围为当前shell进程及其子进程
  •  局部变量:生效范围为当前shell进程中某代码片段(通常指函数)
  •  位置变量:$1,$2,...来表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数
  •  特殊变量:$?,$0,$*,$@,$#

2.5.2.1 本地变量

变量赋值: name='value'

可以使用引用value:

 可以直接是字符串:name="nineven"

 变量引用:name="$USER"

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

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

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

 '':强引用,其中的变量引用不会被替换为变量值,而是保持原字符串

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

删除变量: unset name (删除变量时千万不要加 $ 符号)


实战训练1

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

#!/bin/bash
echo -e  "The computer's info is"
name=$(hostname)
ip=$(ifconfig | sed -rn "s@^[[:space:]]+inet[[:space:]]+(.*)net.*@\1@p"|head -1)
sysinfo=$(cat /etc/centos-release)
kernav=$(uname -r)
cpuinfo=$(lscpu | sed -r -n 's@Model name.*:[[:space:]]+(.*)@\1@p')
meminfo=$( cat /proc/meminfo | head -1)
hhdinfo=$(fdisk -l | head -2|tail -1)
echo -e "\033[31m------主机名----------\033[0m"
echo $name
echo -e "\033[31m--------IPv4地址-----------------\033[0m"
echo -e $ip
echo -e "\033[31m---------操作系统版本-------------\033[0m"
echo $sysinfo
echo -e "\033[31m--------内核版本-----------------\033[0m"
echo $kernav
echo -e "\033[31m-------CPU型号------------------\033[0m"
echo $cpuinfo
echo -e "\033[31m----------内存大小---------------\033[0m"
echo $meminfo
echo -e "\033[31m-----硬盘大小--------------------\033[0m"
echo $hhdinfo
echo -e "\033[31m-------------------------\033[0m"

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

#!/bin/bash
cp -a /etc /root/etc`date +%F`

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

#!/bin/bash
echo "当前硬盘分区利用率最大值是 : `df  | egrep '\/dev\/sda*' | tr -s ' '|cut -d' ' -f5|sort -n|tail -1`"

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

#!/bin/bash
echo "the links number is:"
netstat -nt |tr -s ' '  |cut -d ' ' -f5 |cut -d: -f1 |grep [0-9]|sort |uniq -c|sort -nr


2.5.2.2 环境变量

变量声明,赋值:

 export name=VALUE

 declare -x name=VALUE

变量引用:

$name,${name}

显示所有环境变量:

 export

 env

 printenv

删除:

unset name

bash有许多内建的环境变量:PATH,SHELL,USER,UID,HISTSIZE,HOME,PWD,OLDPWD,HISTFILE,PS1等

2.5.2.3 只读和位置变量

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

 readonly name

 declear -r name

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

 $1,$2,...    #对应第1,第2等参数,shift [n] 换位置

 $0           #命令本身

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

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

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

$@ $*         #只在被双引号包起来的时候才会有差异

比如:判断给出的文件的行数

#!/bin/bash
linecount="$(wc -l $1| cut -d' ' -f1)"
echo "$1 has $linecount lines."

三,shell脚本运算

3.1 算术运算

bash中的算术运算可以通过 help let 命令查看

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

实现算术运算:

 let var=算术表达式

 var=$[算术表达式]

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

 var=$(expr arg1 arg2 arg3 ...)

 declare -i var = 数值

 echo `算术表达式`|bc

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

bash中有内建的随机数生成器:$RANDOM 可以生成 1-32767 ,比如

echo $[$RANDOM%80] :表示0-79之间的随机数
[root@centos7 ~]# echo $[$RANDOM%81]
73
[root@centos7 ~]# echo $[$RANDOM%81]
9
[root@centos7 ~]# echo $[$RANDOM%81]
80

3.2 赋值

增强型赋值:

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

let varOPERvalue

 例如: let count+=3  自加3后的值重新赋给自己

自增,自减:

 let var+=1

 let var++

 let var-=1

 let var--

实战训练2

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

#!/bin/bash
echo "ID sum is : `sed -n '10p;20p' /etc/passwd | cut -d: -f3 | paste -s -d '+'| bc`"

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

#!/bin/bash
echo "文件空白行总共有: `cat $1 $2 | grep -c '^[[:space:]]*$'` 行"

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

#!/bin/bash
echo $[$(ls -a /etc /var /usr |wc -l)-6]

 我感觉 . .. 应该不是子目录吧,所以我在得到的结果减去6


3.3 逻辑运算

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,第二个必须要参与运算

异或:^

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

3.4 聚集命令

有两种聚集命令的方法:

 复合式:date;who |wc -l   命令会一个接一个地运行

 子shell:(date;who |wc -l) >> /tmp/trace  所有的输出都被发送给单个STDOUT和STDERR 

3.5 退出状态及退出码

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

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

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

例如

[root@centos7 testdir]# ping -c1 -W1 10.1.0.1  &> /dev/null
[root@centos7 testdir]# echo $?
0
[root@centos7 testdir]# ping -c1 -W1 10.1.2.1  &> /dev/null
[root@centos7 testdir]# echo $?
1

成功返回0 失败返回非0

bash自定义退出状态码 

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

注意:脚本中一旦遇到exit命令,脚本会立即终止,终止退出状态取决于exit命令后面的数字

    如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

四,测试

4.1 条件测试

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

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

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

 若真,则返回0

 若假,则返回1

测试命令

 test EXPRESSION

 [ EXPRESSION ]

 [[ EXPRESSION ]]

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

4.2 条件性的执行操作符

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

         &&     代表条件性的AND THEN

         ||      代表条件性的OR ELSE

比如:

[root@centos7 testdir]# grep -q root /etc/passwd && echo 'user is exist' || echo 'no user'
user is exist
[root@centos7 testdir]# grep -q roota /etc/passwd && echo 'user is exist' || echo 'no user'
no user

[root@centos7 testdir]# ip="10.1.0.122"
[root@centos7 testdir]# ping -c1 -W1 $ip &> /dev/null && echo 'ip is up' || echo 'ip is down'
ip is down
[root@centos7 testdir]# ip="10.1.0.1"
[root@centos7 testdir]# ping -c1 -W1 $ip &> /dev/null && echo 'ip is up' || echo 'ip is down'
ip is up

4.3 test命令

长格式的例子如下:

[cent@centos7 ~]$ A=abcd
[cent@centos7 ~]$ B=abcd
[cent@centos7 ~]$ test $A == $B && echo 'strings are equal' || echo 'strings are not equal'
strings are equal
[cent@centos7 ~]$ B=abcde
[cent@centos7 ~]$ test $A == $B && echo 'strings are equal' || echo 'strings are not equal'
strings are not equal
[cent@centos7 ~]$ test $A -eq $B && echo 'strings are equal' || echo 'strings are not equal'
-bash: test: abcd: integer expression expected  #字符串不能做 -eq 运算
strings are not equal
[cent@centos7 ~]$ A=18
[cent@centos7 ~]$ B=18
[cent@centos7 ~]$ test $A -eq $B && echo 'Integers are equal' || echo 'Integers are not equal'
Integers are equal
[cent@centos7 ~]$ B=19
[cent@centos7 ~]$ test $A -eq $B && echo 'Integers are equal' || echo 'Integers are not equal'
Integers are not equal

简写格式的例子如下:

[cent@centos7 ~]$ [$A -eq $B] && 'Integers are equal' || echo 'Integers are not equal'
bash: [18: command not found...     # [ EXPRESSION ] ,EXPRESSION表达式前后必须有空白字符
[cent@centos7 ~]$ [ $A -eq $B ] && 'Integers are equal' || echo 'Integers are not equal'
Integers are not equal
[cent@centos7 ~]$ B=18
[cent@centos7 ~]$ [ $A -eq $B ] && echo 'Integers are equal' || echo 'Integers are not equal'
Integers are equal
[cent@centos7 ~]$ A=abcd
[cent@centos7 ~]$ B=abcd
[cent@centos7 ~]$ [ $A == $B ] && echo 'strings are equal' || echo 'strings are not equal'
strings are equal

4.4 bash的测试类型

4.4.1 数值测试

 -gt :是否大于

 -ge :是否大于等于

 -eq :是否等于

 -ne :是否不等于

 -lt :是否小于

 -le :是否小于等于

[cent@centos7 ~]$ A=1;B=4
[cent@centos7 ~]$ [ $A -gt $B ] && echo '成立' || echo '不成立'
不成立    
[cent@centos7 ~]$ [ $A -ge $B ] && echo '成立' || echo '不成立'
不成立
[cent@centos7 ~]$ [ $A -lt $B ] && echo '成立' || echo '不成立'
成立
[cent@centos7 ~]$ [ $A -ne $B ] && echo '成立' || echo '不成立'
成立
[cent@centos7 ~]$ [ $A -eq $B ] && echo '成立' || echo '不成立'
不成立
[cent@centos7 ~]$ [ $A -le $B ] && echo '成立' || echo '不成立'
成立

4.4.2 字符串测试

 ==         :是否等于

 >         :左面的ascii 码是否大于右面字符串的ascii码

 <         :左面的ascii 码是否小于右面字符串的ascii码

 !=         :是否不等于

 =~        :左侧字符串是否能够被右侧的PATTERN所匹配;注意:此表达式一般用于 [[ ]] 中

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

 -n "STRING"         :字符串是否非空,非空为真,空为假

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

参数功能
数值测试
 -gt是否大于
 -ge是否大于等于
 -eq是否等于
 -ne是否不等于
 -lt是否小于
 -le是否小于等于
字符串测试
 ==是否等于
 > ascii码是否大于ascii码 
 <是否小于
 !=是否不等于
 =~左侧字符串是否能够被右侧的PATTERN所匹配 注意: 此表达式一般用于[[]] 中 
 -z "string"字符串是否为空,空为真,不空为假 
 -n "string"字符串是否不空,不空为真,空为假 
注意:用于字符串比较时的用到的操作数都应该使用引号


实战训练3

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

#!/bin/bash
[ $# -ge 1 ] && echo "文件空白行数为: `grep -c '^[[:space:]]*$' $1`" || echo '至少应该给一个参数'

测试执行结果: 

[cent@centos7 scripts]$ bash argsnum.sh /etc/passwd
文件空白行数为: 0
[cent@centos7 scripts]$ bash argsnum.sh /testdir/aa
文件空白行数为: 42
[cent@centos7 scripts]$ bash argsnum.sh 
至少应该给一个参数
 

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

#!/bin/bash
ping -c1 -W1 $1 &> /dev/null && echo "该ip可以访问" || echo "该ip地址不可访问"

测试执行结果:

[cent@centos7 scripts]$ bash hostping.sh 10.1.0.1
该ip可以访问
[cent@centos7 scripts]$ bash hostping.sh 10.1.0.3
该ip地址不可访问

4.4.3 文件测试

参数功能
文件存在性测试
 -e FILE文件存在性测试,存在为真,否则为假
 -a FILE文件存在性测试,存在为真,否则为假
存在性及类别测试
 -b FILE是否存在且为块设备文件
 -c FILE是否存在且为字符文件
 -d FILE是否存在且为目录文件
 -f FILE 或 -L FILE是否存在且为普通文件
 -h FILE是否存在且为符号链接文件
 -p FILE是否存在且为管道文件
 -S FILE是否存在且为套接字文件
文件权限测试
 -r FILE是否存在且可读
 -w FILE是否存在且可写
 -x FILE是否存在且可执行
文件特殊权限测试
 -g FILE是否存在且拥有sgid权限
 -u FILE是否存在且拥有suid权限
 -k FILE是否存在且拥有sticky权限
文件大小测试
 -s FILE是否存在且非空
文件是否打开
 -t fdfd表示文件描述符是否存在已经打开且与某终端相关
 -N FILE文件自动上一次被读取之后是否被修改过
 -O FILE当前有效用户是否为文件属主
 -G FILE当前有效用户是否为文件属组
双目测试
FILE1 -ef FILE2FILE1与FILE2是否指向同一个设备上的相同的inode
FILE1 -nt FILE2FILE1是否新于FILE2
FILE1 -ot FILE2

FILE1是否旧于FILE2

4.4.4 组合测试

第一种方式

 COMMAND1 && COMMAND2 并且

 COMMADN1 || COMMAND2 或者

 !COMMAND 非

第二种方式

 EXPRESSION1 -a EXPRESSION2 并且

 EXPRESSION1 -o EXPRESSION2 或者

 !EXPRESSION 非

 必须使用测试命令进行

[ -z "$HOSTNAME" -o $HOSTNAME == "localhost.localdomain" ] && hostname www.liuyuworld.com
### 判断hostname是否为空或者hostname是"localhost.localdomain" 如果前面有一个条件成立,然后执行hostname 命令
[ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab ##判断文件是否存在并且可执行


实战训练4

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

#!/bin/bash
[ ! -r /tmp/file1 ] && [ ! -w /tmp/file1 ] && echo "不可读写" || echo "可读写"
执行结果:
[root@centos7 shell]# chmod -rw /tmp/file1 
[root@centos7 shell]# ll /tmp/file1 
----------. 1 root root 0 Aug 10 16:22 /tmp/file1
[root@centos7 shell]# bash per.sh 
可读写
[root@centos7 shell]# su cent
[cent@centos7 shell]$ bash per.sh 
不可读写

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

思路:当/etc/目录下存在 nologin 文件时,普通用户会无法登陆,因此,我们只需要通过删除或增加该文件来限制普通用户是否可登陆

[root@centos7 shell]# cat login.sh 
#!/bin/bash
[ -e /etc/nologin ] && echo "`rm -f /etc/nologin` enable user login "

[root@centos7 shell]# cat nologin.sh 
#!/bin/bash
[ -a /etc/nologin ]  ||  touch /etc/nologin
echo "disable user login "

执行 bash nologin.sh 脚本时,登陆普通用户会提示

Connecting to 172.18.16.152:22...
Connection established.
To escape to local shell, press 'Ctrl+Alt+]'.
Connection closed by foreign host.
Disconnected from remote host(centos7) at 20:11:18.

然后执行bash login.sh 脚本时,就可以直接登陆了

Connecting to 172.18.16.152:22...
Connection established.
To escape to local shell, press 'Ctrl+Alt+]'.
Last failed login: Fri Aug 12 20:11:09 CST 2016 from 172.18.16.171 on ssh:notty
There was 1 failed login attempt since the last successful login.
Last login: Fri Aug 12 20:10:29 2016 from 172.18.16.171

生成01-20

 seq -f'%02g' 1 20 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值