shell脚本编程基础

一、编程基础

程序:算法+数据结构
数据:是程序的核心
数据结构:数据在计算机中的类型和组织方式
算法:处理数据的方式  

程序编程风格:

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

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

二、程序运行方式

  • 编译:高级语言-->编译器-->机器代码-->执行

           C,C++

  •  解释:高级语言-->执行-->解释器-->机器代码

          shell,python,php,JavaScript,perl

(1)编译运行:源代码需要编译器转换为程序文件,运行程序文件时不需要编译器的参与,因此程序执行效率高
    比如:C语言,独立的编程语言,通常通过调用函数库中的或类库中的函数来运行,无须调用外来的库
(2)解释运行:源代码不需要事先编译,运行时启动解释器而后由解释器边解释边运行,因此效率比较低
    比如我们将要讲到的bash脚本编程

根据编程过程中实现是调用库还是调用外部的程序文件

(1).shell脚本编程:非完整编程语言
  利用系统上的命令及编程组件进行编程
(2).非shell脚本编程:完整的编程语言
  利用库和编程组件进行编程

三、编程基本概念

编程逻辑处理方式:

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

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

编程语言的基本结构:

各种系统命令的组合
数据存储:变量、数组
表达式: a + b
语句:if

根据编程模型分类

(1).面向过程编程语言

以指令为中心来组织代码,以过程或函数为基础,数据服务于代码,围绕指令来组织数据;这种语言对底层硬件,内存等操作比较方便,但是写代码和调试维护等会很麻烦。
他们按照顺序执行,选择执行,循环执行
这其中的代表语言有:C bash C++ python

(2).面向对象的编程语言

以数据为中心来组织代码,以对象作为基本程序结构单位的程序设计语言,指令服务于数据,围绕数据来组织指令;指用于描述的设计是以对象为核心,而对象是程序运行时刻的基本成分。语言中提供了类、继承等成分。
对象:特定的数据类型
类class:实例化成为对象
代表:Java C++ python

综上所述可知shell脚本编程属于解释运行的过程式编程语言且依赖于外部程序文件来运行

四、shell脚本基础

shell脚本:

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

格式要求:首行shebang机制,以#!/bin/bash开始

#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl

shell脚本的用途有:

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

创建shell脚本

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

第一行必须包括shell声明序列:#!
#!/bin/bash
添加注释
注释以#开头

第二步:运行脚本

给予执行权限,在命令行上指定脚本的绝对或相对路径
直接运行解释器,将脚本作为解释器程序的参数运行

脚本规范 

脚本代码开头约定

1、第一行一般为调用使用的语言
2、程序名,避免更改文件名为无法找到正确的文件
3、版本号
4、更改后的时间
5、作者相关信息
6、该程序的作用,及注意事项
7、最后是各版本的更新简要说明

脚本示例:

#!/bin/bash
# ------------------------------------------
# Filename: hello.sh
# Revision: 1.1
# Date: 2017/06/01
# Author: wang
# Email: wang@gmail.com
# Website: www.magedu.com
# Description: This is the first script
# ------------------------------------------
# Copyright: 2017 wang
# License: GPL
echo “hello world”

脚本调试

检测脚本中的语法错误
bash -n /path/to/some_script
调试执行
bash -x /path/to/some_script

五、bash的配置文件

bash配置按照对象分两类

1. profile为交互式登录的shell进程提供配置

直接通过某终端输入账号密码后登录打开的shell进程
使用su - wang或使用su - l wang执行的登录切换,会通过重新读取目标用户的配置文件来重新初始化

profile配置文件的作用与作用域:为交互式登录的shell提供配置

1、全局配置:对所有用户都生效,定义用户的环境变量,配置文件存放于/etc/profile ,/etc/profile.d/*.sh
2、运行命令或脚本,配置文件存放于/etc/profild.d/*.sh 以sh结尾的文件
3、个人用户:仅对当前用户有效,文件存放于用户家目录~/.bash_profile
4、对交互式登录shell进程顺序,配置文件读取次序
/etc/profile --> /etc/profile.d/* --> ~/bash_profile --> ~/.bashrc --> /etc/bashrc

2. bashrc为非交互式登录的shell进程提供配置

如 su sanxi执行的登录切换,不会读取目标用户的配置文件进行初始化
如 在图形界面打开的终端
如 运行脚本

bashrc配置文件的作用及作用域:为非交互式和交互式登录的shell提供配置

1、定义本地变量,仅对当前shell进程有效
2、定义命令别名,可定义当前用户与全局
3、全局配置文件存放于/etc/bashrc
4、个人用户:用户家目录下的~/.bashrc
5、对非交互式登录shell进程,配置文件读取次序
 /etc/profile.d/*.sh --> /etc/bashrc-->~/.bashrc

(1)命令中定义的特性,譬如变量和别名作用域仅对当前shell进程有效

(2)配置文件中定义的特性,只对随后新启动的shell进程有效

让通过配置文件定义的特性立即生效,命令行重复定义一次,让shell进程重读配置文件source /PATH/FROM/CONF_FILE,如下

[root@test-edu ~]# source .bashrc 
. /PATH/FROM/CONF_FILE 如[root@test-edu ~]# . /etc/profile

 注意:仅管理员可修改全局配置文件

 Bash 退出任务

 保存在~/.bash_logout文件中(用户)

 在退出登录shell时运行。

 用于

•创建自动备份
•清除临时文件

示例:在 家目录.bash_logout文件里输入rm  -rf  /data/test,当退出登录时,就会执行此命令,删除临时文件。

[root@centos7~]#vim ~/.bash_logout

 

那么,什么是bash脚本呢?

一种为shell编写的脚本程序;是Linux命令的堆砌;但由于Linux中很多命令不具有幂等性,需要设定程序逻辑来判断运行条件是否满足,以避免其运行中发生错误

何为幂等性?

   即一个操作,不论执行多少次,产生的效果和返回的结果都是一样的,这样的操作的特性我们就叫幂等性!

如何运行脚本?

1.赋予执行权限,并直接运行此程序文件
chmod +x test.sh 赋予test.sh文件以执行权限 #权限的相关解释说明请看本人上一章Linux用户权限管理
./test.sh 注意,要指定路径告诉系统在哪里可以找到sh文件,否则系统会去PATH里找

2.指定解释器运行,将脚本当作解释器的参数来运行,因此不需要文件的执行权限,直接用bash执行脚本命令:

vim hello.sh
#!/bin/bash
echo "hello world!"

[root@centos7-1data]#bash hello.sh
hello world!

将当前的shell脚本的路径添加到path变量中,给shell脚本加上执行权限,可以直接输入脚本名称执行脚本

vim test.sh
#!/bin/bash
echo "your time is "
date +"%F-%T"
chmod +x  test.sh   #给脚本加上执行权限
vim /etc/profile.d/shell.sh  将脚本路径写入到PATH变量中
PATH=/data:$PATH 
. /etc/profile.d/shell.sh   将变量路径生效
[root@centos7-1data]#test.sh   执行脚本
your time is 
2019-11-16-23:55:06

六、变量  

变量:命名的内存空间

数据存储方式:
字符:
数值:整型,浮点型

变量:变量类型

作用:
    1、数据存储格式
    2、参与的运算
    3、表示的数据范围
类型:
字符
数值:整型、浮点型

强类型:

变量不经过强制转换,它永远是这个数据类型,不允许隐式的类型转换。一般定义变量时必须指定类型、参与运算必须符合类型要求;调用未声明变量会产生错误
如:java , c# ,python
如:print(‘magedu’+ 10) 提示出错,不会自动转换类型
print(‘magedu’+str(10)) 结果为magedu10,需要显示转换类型

弱类型:

语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会自动进行隐式类型转换;变量无须事先定义可直接调用
如:bash 不支持浮点数,php,javascript

变量命名法则:

1、不能使程序中的保留字:例如if, for
2、只能使用数字、字母及下划线,且不能以数字开头
3、见名知义
4、统一命名规则:驼峰命名法
例如: 
大驼峰:StudentName
小驼峰:sTUDENTnAME

七、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

示例:

[root@centos7-1~]#student_num=10   将student_num 赋予变量10
[root@centos7-1~]#echo "my student id is $student_num"
my student id is 10
[root@centos7-1~]#name=wang
[root@centos7-1~]#echo "my name is $name$student_num"
my name is wang10
[root@centos7-1~]#echo "my name is ${name}$student_num"  两个变量都生效 都必须有$变量,然后前面的变量用{}括起来。
my name is wang10

 

示例;

写脚本时,需要加上脚本的注释信息,避免后期维护时已不知道当前写的信息内容是什么意思

#!/bin/bash
#
#********************************************************************
#Author:                liudalao
#QQ:                    77421225
#Date:                  2019-11-17
#FileName:             sysinfo.sh
#URL:                   http://www.struggle.com
#Description:          The test script
#Copyright (C):         2019 All rights reserved
#********************************************************************

#RED is content  color
#RED1 is content color
RED="\033[1;36m"                                                                                                                                 
RED1="\033[0m"
echo -e OS version is $RED`cat /etc/centos-release`$RED1
echo -e disk used is $RED`df | grep /dev/sd | tr -s " " |cut -d" " -f5 | sort -nr | head -n1`$RED1
echo -e kernel is $RED`uname -r`$RED1
echo -e "host name  is  $RED`hostname`"$RED1
unset RED RED1

   

执行脚本:

  

示例一:演示当前父进程和子进程区别

[root@centos7-1scripts]#name=m34;(echo $name;name=net34;echo $name);echo $name  小括号会开启子进程,赋予变量,只在小括号内有效
m34
net34
m34

示例:

[root@centos7-1scripts]#name=m34;{ echo $name;name=net34;echo $name; };echo $name   大括号不会开启子进程,只在当前进程有效
m34
net34
net34

echo $$和echo $BASHPID区别:两者都是显示当前进程的编号,但是echo $BASHPID更精确

环境变量

变量声明、赋值:
export name=VALUE
declare -x name=VALUE
变量引用:$name, ${name}
显示所有环境变量:
env
printenv
export
declare -x
删除变量:
unset name

演示:直接将mm赋予变量wang,当开启子进程时,无法找到变量,如果赋予环境变量export ,就会显示父进程的变量结果。

 

bash内建的环境变量:

PATH
SHELL
USER
UID
HOME
PWD
SHLVL
LANG
MAIL
HOSTNAME
HISTSIZE
—

只读和位置变量

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

readonly name
declare -r name

查看只读变量:

readonly –p

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

$1, $2, ...:对应第1、第2等参数,shift [n]换位置
$0: # 脚本文件路径本身
$*: # 传递给脚本的所有参数,全部参数合为一个字符串
$@: # 传递给脚本的所有参数,每个参数为独立字符串
$#: # 传递给脚本的参数的个数
$@ $* # 只在被双引号包起来的时候才会有差异
set --:清空所有位置变量

 示例:

 $1 代表第几个参数

  

 执行脚本:

  

 示例:

写入所有位置变量传递参数的脚本

  

 执行脚本显示结果:

  

 示例:

$*和$@的区别:

  • $*将每个参数认为是一个字符串
  • $@将每个参数认为是独立的字符串 

示例:

在test2.sh中写入脚本,将$*传递给test1.sh

 

 在test1.sh内写入传递的一个参数

 

 执行$*的脚本内容:可以看出$*将参数当成一个字符串

 

执行$@的脚本内容:$@将每个参数当成一个参数

 

 示例:

在不同centos版本上输入不同的网卡名称,可以截取出IP地址:

 

执行脚本:

 

示例:

创建一个脚本代码开头:

cat > $1 <<EOF
#!/bin/bash
#
#********************************************************************
#Author:                liudalao
#QQ:                    77421225
#Date:                  `date +%F`
#FileName:             $1      将此处进行修改
#URL:                   http://www.struggle.com
#Description:          The test script
#Copyright (C):         2019 All rights reserved
#********************************************************************
EOF
chmod +x  $1
vim +  $1 

 

 创建一个ll.sh脚本内容:

[root@centos7-1scripts]#createscripts_N.sh ll.sh 创建一个ll.sh脚本
[root@centos7-1scripts]#ll.sh  执行脚本,查看脚本创建的内容
centos7-1

 

八、退出状态

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

• 0 代表成功,1-255代表失败
• $? 变量保存最近的命令退出状态
例如:
ping -c1 -W1 hostdown &> /dev/null
echo $?
退出状态码

注意:echo $?只保存最后一次的执行状态

示例:

 

此时执行脚本的结果有错误,但是最后一次是正确的语法内容,因此echo $? 就会返回0,只记录最后一次的执行状态。

  

bash自定义退出状态码

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

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

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

赋予一个脚本的exit 状态码100,可以用echo $? 输出结果100,表示一种脚本执行的执行状态

  

 执行脚本结果:

 

九、算术运算

bash中的算术运算:help let

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

实现算术运算:

(1) let var=算术表达式
(2) var=$[算术表达式]
(3) var=$((算术表达式))
(4) var=$(expr arg1 arg2 arg3 ...)
(5) declare –i var = 数值
(6) echo ‘算术表达式’ | bc
乘法符号有些场景中需要转义,如*
bash有内建的随机数生成器:$RANDOM(0-32767)
  echo $[$RANDOM%50] :0-49之间随机数

赋值

增强型赋值:

+=, -=, *=, /=, %=
let varOPERvalue

例如:let count+=3
自加3后自赋值
自增,自减:

let var+=1
let var++
let var-=1
let var--

示例:

 

 示例:

[root@centos7-1scripts]#i=10;let j=i++;echo $j    i++是赋值后加
10 
[root@centos7-1scripts]#i=10;let j=++i;echo $j    ++i是先加后赋值
11

 

示例:取1-63的模,其中RANDOM%63 是0-62的值,加1就是1-63

[root@centos7-1scripts]#echo $[RANDOM%63+1]
14

示例:生成随机的颜色

echo -e  "\033[1;$[RANDOM%7+31]m 你好\033[0m"  

 

 执行脚本:

 

示例:自己累加:let i+=10,i+=i,

 

逻辑运算

true, false
1, 0
与:(&)只要和0与全是0

1 与 1 = 1
1 与 0 = 0
0 与 1 = 0
0 与 0 = 0

或:(|)只要和1与全是1

1 或 1 = 1
1 或 0 = 1
0 或 1 = 1
0 或 0 = 0

逻辑运算
非:!

! 1 = 0 ! true
! 0 = 1 ! false

短路运算

短路与(&&)

第一个为0,结果必定为0
第一个为1,第二个必须要参与运算 

总结:如果命令1为真,就执行命令2,如果命令1为假,命令2不执行

短路或(||)

第一个为1,结果必定为1
第一个为0,第二个必须要参与运算

总结:如果命令1为真,不执行命令2,如果命令1为假,命令2就执行。

异或:^

异或的两个值,相同为假,不同为真  0^0为假(0) 0^1为真(1)

同或:

同或的两个值,相同为真,不同为假  0^0为真(1)  0^1为假(0)

示例:数字进行互换

[root@centos7-1scripts]#A=10,B=20;A=$[A^B];B=$[A^B];A=$[A^B];echo A=$A B=$B  
A=20 B=20

 

条件测试

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

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

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

• 若真,则返回0
• 若假,则返回1

测试命令:

• test EXPRESSION
• [ EXPRESSION ]
• [[ EXPRESSION ]] 支持正则表达式和通配符

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

 示例:

测试字符串的真假:放到中括号里边做比较,一定要加双引号。

 

test命令

长格式的例子:

test "$A" = "$B" && echo "Strings are equal"
test “$A”-eq “$B” && echo "Integers are equal"

简写格式的例子:

[ "$A" = "$B" ] && echo "Strings are equal"
[ "$A" -eq "$B" ] && echo "Integers are equal"

bash的数值测式

-v VAR
      变量VAR是否设置
数值测试:

-gt 是否大于
-ge 是否大于等于
-eq 是否等于
-ne 是否不等于
-lt 是否小于
-le 是否小于等于

bash字符串测试:

= 是否等于
> ascii码是否大于ascii码
< 是否小于
!= 是否不等于
=~ 左侧字符串是否能够被右侧的PATTERN所匹配   支持正则表达式 写法[[ A =~ B  ]]

注意: 此表达式一般用于[[ ]]中;扩展的正则表达式

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

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

示例:

[-z  "$path"] 判断$path变量是否为空。 

示例:

  

条件性的执行操作符

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

•&& 代表条件性的AND THEN,如果第一个条件存在,则会执行第二条命令。
•|| 代表条件性的OR ELSE,如果第一个条件存在,不执行第二条命令,而不存在,就执行第二条命令。

示例:

[root@cenots47~]#false && echo true  如果第一条命令错误,则不执行第二条true命令
[root@cenots47~]#true  && echo true   如果第一条命令正确,则会执行第二条命令
true
[root@cenots47~]#false || echo true  如果第一条命令错误,则执行第一条命令
true
[root@cenots47~]#true  || echo true  如果第一条命令正确,则不执行第一条命令

示例:如果用户存在,则不创建用户,如果不存在就会创建一个用户

[root@cenots47~]#username=user1;id $username &> /dev/null || useradd $username    如果有user1用户,则不会创建用户,如果不存在,就会创建用户账号。
[root@cenots47~]#getent passwd
user1:x:1001:1001::/home/user1:/bin/bash

示例:判断年龄进行打印

[root@cenots47~]#age=20;[ "$age" -gt 18 ] && echo too old || echo too young   当判断年龄的第一条命令为真,就会执行短路与的结果
 too old
[root@cenots47~]#age=15;[ "$age" -gt 18 ] && echo too old || echo too young   当判断年龄的第一条命令为假,就会执行短路或的结果
 too young

 

 演示,当磁盘大于15%,就进行报警脚本

#!/bin/bash
#
#********************************************************************
#Author:                liu
#QQ:                    29308620
#Date:                  2019-12-18
#FileName:             chdisk.sh
#URL:                   http://www.struggle.com
#Description:          The test script
#Copyright (C):         2019 All rights reserved
#********************************************************************
warning=15                                                                                                                                       
disk=`df | grep "^/dev/sda*" | tr -s ' ' % | cut -d% -f5 |sort -nr |head -n1`
[ $disk  -gt  $warning ]  &&  wall disk will full

  

 执行脚本:

[root@centos7data]#bash chdisk.sh 

Broadcast message from root@centos7 (pts/0) (Wed Dec 18 11:41:44 2019):

disk will full

演示:

 当输入IP地址不是本机的就打印down,是本机的就打印up,未输入IP地址就请用户输入IP地址

#!/bin/bash
#
#********************************************************************
#Author:                liu
#QQ:                    29308620
#Date:                  2019-12-18
#FileName:             ip.sh
#URL:                   http://www.struggle.com
#Description:          The test script
#Copyright (C):         2019 All rights reserved
#********************************************************************
[ $# -eq 0 ] && echo "Please input a canshu" && exit 1
ping -c1 -w1 $1 &> /dev/null && echo "The host is up" || echo "The host is down"  

  

 脚本执行效果:

[root@centos7data]#bash ip.sh 
Please input a canshu
[root@centos7data]#bash ip.sh 192.168.37.7
The host is up
[root@centos7data]#bash ip.sh 192.168.37.11
The host is down

  

bash字符串测试:

= 是否等于
> ascii码是否大于ascii码
< 是否小于
!= 是否不等于
=~ 左侧字符串是否能够被右侧的PATTERN所匹配   支持正则表达式 写法[[ A =~ B  ]]

注意: 此表达式一般用于[[ ]]中;扩展的正则表达式

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

示例:

[-z  "$path"] 判断$path变量是否为空。 

示例:

  

 通配符写法示例:

[root@centos7data]#str=abcdef;[[ "$str" =~ abc* ]] && echo ture || echo false  abc*通配符不能加上双引号
ture
[root@centos7data]#str=abc;[[ "$str" == ??? ]] && echo ture || echo false
ture

 正则表达式写法:

[root@centos7data]#str=abcdef;[[ "$str" =~ ^abc ]] && echo ture || echo false   判断以^abc开头的字符
ture
[root@centos7data]#str=abcdef;[[ "$str" =~ ^$ ]] && echo ture || echo false   判断$str字符串为空串
false
[root@centos7data]#str=abcdef;[[ "$str2" =~ ^$ ]] && echo ture || echo false    判断$str2字符串为空串
ture
[root@centos7data]#str=a.sh;[[ "$str" =~ \.sh$ ]] && echo ture || echo false    判断文件后缀是以.sh的文件,需要将.进行转义。
ture

  示例:判断用户名是否存在,存在就显示已存在,并退出

#!/bin/bash
#
#********************************************************************
#Author:                liu
#QQ:                    29308620
#Date:                  2019-12-18
#FileName:             useradd.sh
#URL:                   http://www.struggle.com
#Description:          The test script
#Copyright (C):         2019 All rights reserved
#********************************************************************
id $1 &> /dev/null && { echo $1 is exist;exit; }  || ( useradd $1 ;echo $1 is created )  判断输入的用户名是否存在,已存在就退出,不存在就进行新建用户名,其中第一个大括号是退出所有进程,如果用小括号,只是退出当前的进程。
echo finished  

 执行脚本,查看效果:

 

带小括号和不带小括号的用法:

[root@centos7~]#( cd /data/test ;rm -rf *)  如上所说,带小括号,执行完命令后,就会退出当前的目录子进程。
[root@centos7~]# cd /data/test ;rm -rf *     不带小括号就会切换到目录下执行命令,并不会退出。
[root@centos7test]#

 Bash的文件测试 

  存在性测试

-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: 是否存在且可执行

 文件特殊权限测试:

-u FILE:是否存在且拥有suid权限
-g FILE:是否存在且拥有sgid权限
-k FILE:是否存在且拥有sticky权限

  文件大小测试:

-s FILE: 是否存在且非空

  文件是否打开:

-t fd: fd文件描述符是否在某终端已经打开
-N FILE:文件自从上一次被读取之后是否被修改过
-O FILE:当前有效用户是否为文件属主
-G FILE:当前有效用户是否为文件属组 

  双目测试:

FILE1 -efFILE2: FILE1是否是FILE2的硬链接
FILE1 -ntFILE2: FILE1是否新于FILE2(mtime)
FILE1 -otFILE2: FILE1是否旧于FILE2

  示例:

[root@centos7data]#[ -f /etc/passwd ] && echo true ||echo false  判断此文件是否存在,存在就显示true,不存在就显示false
true
[root@centos7data]#[ -x /data/test.txt ]  && echo true ||echo false  判断文件是否有执行权限,有执行权限就显示true,无执行权限就显示false
false

[root@centos7data]#file=ip.sh;[[ $file =~ \.sh$ ]] && [ ! -x $file ] && chmod +x $file  判断ip.sh是否是.sh后缀的文件,并判断是否有执行权限,如果有就加上执行权限。
[root@centos7data]#ll ip.sh 
-rwxr-xr-x 1 root root 500 Dec 18 15:17 ip.sh

 Bash的组合测试条件 

    第一种方式:

COMMAND1 && COMMAND2 并且
COMMAND1 || COMMAND2 或者
! COMMAND 非
如:[ -f “$FILE” ] && [[ “$FILE”=~ .*\.sh$ ]]

第二种方式:

EXPRESSION1 -a EXPRESSION2 并且
EXPRESSION1 -o EXPRESSION2 或者
! EXPRESSION
必须使用测试命令进行,[[ ]] 不支持

  示例:

[ -z “$HOSTNAME” -o $HOSTNAME "=="localhost.localdomain" ]  && hostname www.magedu.com   判断字符串是否为空或者字符为localhost.localdomain,则打印hostname www.magedu.com
[ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab  

  示例: 判断有读权限且有写权限时,去掉写权限。

[root@centos7data]#file=ip.sh;[ -r "$file" -a -w "$file" ] && chmod -w $file

 注意:在使用通配符和正则表达式时,可以使用双中括号[[  ]],其他用单括号 [  ]。  

使用read命令来接受输入

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

-p指定要显示的提示
-s 静默输入,一般用于密码,加入此选项,一般输入密码不会被看到
-n N指定输入的字符长度N
-d‘字符’ 输入结束符
-t N TIMEOUT为N秒

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

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

read -p “Enter a filename:“ FILE

示例:

#!/bin/bash
#
#********************************************************************
#Author:                liu
#QQ:                    29308620
#Date:                  2019-12-18
#FileName:             read.sh
#URL:                   http://www.struggle.com
#Description:          The test script
#Copyright (C):         2019 All rights reserved
#********************************************************************
read -p "please input username: " name
read -s -p "please input password: " pass
echo       加入此行,作用为了换行。                                                                                                                                      
echo your name is $name
echo your pass is $pass

 

 执行脚本效果:

 

  示例:

  read -n 限制字符个数

  read  -d 以什么作为结束

  read -t  限制超时时长

 

 鸡兔同笼脚本

 输入头数:35     输入脚个数:94

 几只鸡:x         几只兔:y

  算法:

  第一种算法、x+y=35(头数)   2x+4y=94(脚数)

  第二种算法、94/2=47-35=12(兔子个数)   35-12=23(鸡个数)

  let用法:

#!/bin/bash
#
#********************************************************************
#Author:                liu
#QQ:                    29308620
#Date:                  2019-12-18
#FileName:             tuzi.sh
#URL:                   http://www.struggle.com
#Description:          The test script
#Copyright (C):         2019 All rights reserved
#********************************************************************
read  -p "please input floot num: " floot
read  -p "please input head num: " head                                                                                                          
let  x=$floot/2-$head
let  y=$head-$x
echo "rabbit=$x;chook=$y"   

  [  ]用法:

#!/bin/bash
#
#********************************************************************
#Author:                liu
#QQ:                    29308620
#Date:                  2019-12-18
#FileName:             tuzi.sh
#URL:                   http://www.struggle.com
#Description:          The test script
#Copyright (C):         2019 All rights reserved
#********************************************************************
read  -p "please input floot num: " floot
read  -p "please input head num: " head
rabbit=$[(floot-2*head)/2]                                                                                                                       
chook=$[$head-$rabbit]
echo "rabbit=$rabbit;chook=$chook"

  执行脚本效果

[root@centos7data]#bash rabbit_chook.sh  执行结果
please input floot num: 50
please input head num: 20
rabbit=5;chook=15

bash如何展开命令行  

  • 把命令行分成单个命令词
  • 展开别名
  • 展开大括号的声明({})
  • 展开波浪符声明(~)
  • 命令替换$()和``)
  • 再次把命令行分成命令词
  • 展开文件通配(*、?、[abc]等等)
  • 准备I/0重导向(<、>)
  • 运行命令

 防止扩展 

反斜线(\)会使随后的字符按原意解释

$echoYourcost:\$5.00
Yourcost:$5.00

加引号来防止扩展
•单引号(’)防止所有扩展
•双引号(”)也防止所有扩展,但是以下情况例外:

$(美元符号)-变量扩展
`(反引号)-命令替换
\(反斜线)-禁止单个字符扩展,转义单个字符
!(叹号)-历史命令替换

  

 

  

  

 

 

 

  

 

  

  

 

  

  

  

  

 

 

  

  

 

  

  




posted @ 2019-12-18 17:49  一叶知秋~~  阅读(647)  评论(0编辑  收藏  举报