1.8 linux基础(八)-shell脚本基础

1.8 linux基础(八)-shell脚本基础

1.8.1、创建shell脚本

  • 使用文本编辑器vim来创建文本文件
  • 第一行必须包括shell声明序列:#!(幻数)
  • #!/bin/bash
  • 添加注释,注释以#开头 (尽量不要用中文)

1.8.2 脚本的执行方式

  • bash script-name.sh
  • /path/to/script-name.sh或者 ./script-name.sh 脚本需要有执行权限才行
给脚本增加执行权限:
chmod +x script-name.sh
  • source或. script-name
    • 注意:会将脚本中的变量值或函数返回值传递到父shell中,会在当前shell中执行加载脚本中的变量命令,而不是产生子shell去执行脚本。a,b都是产生子shell执行的脚步。
[root@CentOS7 data]# cat source.sh
#!/bin/bash 
#
name=10000 
[root@CentOS7 data]# name=0 
[root@CentOS7 data]# echo $name
0
[root@CentOS7 data]# sh source.sh
[root@CentOS7 data]# echo $name 
0
[root@CentOS7 data]# . source.sh
[root@CentOS7 data]# echo $name
10000
[root@CentOS7 data]# cat source2.sh
echo $name
[root@CentOS7 data]# . source2.sh
10000 ##一个脚本调用另一个脚本的参数

1.8.3、脚本规范

脚本代码开头约定

1、第一行一般为调用使用的语言

2、程序名,避免更改文件名为无法找到正确的文件

3、版本号

4、更改后的时间

5、作者相关信息

6、该程序的作用,及注意事项

7、最后是各版本的更新简要说明

#!/bin/bash
# ------------------------------------------
# Filename: hello.sh
# Revision: 1.1
# Date: 2018/08/01
# Author: zhu
# Email: xxx@qq.com
# Website: www.xxx.com
# Description: This is the first script
# ------------------------------------------
# Copyright: 2018 zhu
# License: GPL
echo “hello world

1.8.4 脚本调试

检测脚本中的语法错误bash -n /path/to/some_script

调试分步执行bash -x /path/to/some_scrip

1.8.5 养成脚本编写的好习惯

  • 成对符号一次性打出来,然后退格在符号里添加内容,防止遗漏
  • []中括号,[[]]两端必须都有两个空格
  • 流程控制语句,一次性将格式这写完,在添加内容
  • 通过缩进让代码易读
  • 常规变量的字符串定义变量值应该加号,并且等号前后不能有空格,需要强引用的,用'',如果是命令的引用,则用双引号""
  • linux中的符号都是英文状态下的符号

1.8.6 编写第一个脚本hello world

[root@CentOS7 ~]# vim test1.sh
[root@CentOS7 ~]# cat test1.sh
#!/bin/bash

# ------------------------------------------

# Filename: test1.sh

# Revision: 1.1

# Date: 2018/08/01

# Author: zhu

# Email: 154760531@qq.com

# Website: www.studylinux.net

# Description: This is the first script

# ------------------------------------------

# Copyright: 2018 zhu

# License: GPL

echo "hello world"

1.8.7 写一个脚本脚本/root/bin/systeminfo.sh,显示当前主机系统信息

包括主机名, IPv4地址,操作系统版本,内核版本,CPU型号,内存大小,硬盘大小

[root@CentOS7 ~]# cat /root/bin/systeminfo.sh
#!/bin/bash 
echo "OS_version is  `cat /etc/centos-release| grep -o "[0-9]\+"|head -n1`"
echo "Kernel_version is `uname -r`"
echo "IPv4 is `ifconfig ens33|grep "cast"|tr -s ' ' |cut -d" " -f3`"
echo "CPU_type is `lscpu |grep "Model name"|tr -s " " |cut -d: -f2`"
echo "Memory Size is `cat /proc/meminfo |head -n1 |tr -d " "|cut -d: -f2`"
lsblk|grep "^sd"|tr -s " "|cut -d " "  -f1,4`"
echo "Hostname is $HOSTNAME"
echo "My name is "$USER""

1.8.8 变量

  • 变量:命名的内存空间

  • 数据存储方式:ASCII

    • 字符:110
    • 数值:110
  • 变量作用:

    • 1、数据存储格式
    • 2、参与的运算
    • 3、表示的数据范围
  • 变量类型:

    • 字符
    • 数值:整型、浮点型
  • 强类型:变量在使用前,必须事先声明,甚至还需要初始化

  • 弱类型:变量在使用前,不需要事先声明,参与运算会自动进行隐式类型转换。默认为字符形式,bash不支持浮点型。

  • 变量命名法则:

    • 1、不能使程序中的保留字:例如if, for
    • 2、只能使用数字、字母及下划线,且不能以数字开头
    • 3、见名知义
    • 4、统一命名规则:驼峰命名法
  • 根据变量的生效范围等标准划分下面变量类型:

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

  • 环境(全局)变量:生效范围为当前shell进程及其子进程

  • 本地变量:生效范围为当前shell进程中某代码片断,通常指函数

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

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

  • $$:当前进程的PID

  • $!:执行上一个指令的PID

1.8.8.1 局部变量

  • 变量赋值:name=‘value’
  • 可以使用引用value:
    • (1) 可以是直接字串; name=“root"
    • (2) 变量引用:name="$USER"
    • (3)命令引用:name=`COMMAND` name=$(COMMAND)
  • 变量引用:${name} $name
    • "":弱引用,其中的变量引用会被替换为变量值
    • '':强引用,其中的变量引用不会被替换为变量值,而保持原字符串
  • 显示已定义的所有变量:set
  • 删除变量:unset name

1.8.8.2环境变量

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

1.8.8.3 只读变量

  • 只读变量:只能声明,但不能修改和删除
  • 声明只读变量:
    • readonly name
    • declare -r name
  • 查看只读变量: readonly –p

1.8.8.4 位置变量

  • 位置变量:在脚本代码中调用通过命令行传递给脚本的参数
  • $1, $2, ...:对应第1、第2等参数,
  • shift [n]换位置
  • $0: 命令本身
  • "$*":传递给脚本的所有参数,全部参数合为一个字符串,相当于"$1 $2 $3"
  • "$@": 传递给脚本的所有参数,会保留所有的内嵌在每个参数中的任何空白,将所有参数视为不同的独立字符串,相当于"$1" "$2" "$3"
  • $#: 传递给脚本的参数的个数
  • $@: 传递给脚本的所有参数
  • $*: 引用传递给脚本的所有参数,只在被双引号包起来的时候$*和$#才会有差异。
  • set -- 清空所有位置变量
[root@CentOS7 ~]#  name=parent;{ echo "1:$name";name=son;echo "2:$name"; };echo "3:$name"
1:parent  ## 花扩号在当前shell中执行,前后有空格,不开启子shell
2:son
3:son
[root@CentOS7 ~]#  name=parent;(echo "1:$name";name=son;echo "2:$name");echo "3:$name"
1:parent  ## 小括号在执行时,会开启子进程,子进程能拿到父进程的变量,子进程内变量赋值、内部命令将会影响子进程的环境,()执行完成后,子进程结束,不保留变量赋值。
2:son
3:parent

1.8.9 $?命令执行状态返回值(退出状态)

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

  • 0 代表成功 1-255代表失败
  • $? 变量保存上一条命令执行状态返回值
  • 例如: ping -c1 -W1 hostdown &> /dev/null echo $?

1.8.10 退出状态码

  • bash自定义退出状态码
  • exit [n]:自定义退出状态码
  • 注意:脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命 令后面的数字 注意:如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

1.8.11 算术运算

  • bash中的算术运算:bash会对数字执行隐式的类型转换
  • 运算操作符:+, -, *, /, %取模(取余), **(乘方)
  • 实现算术运算:
  • (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 即count=count+3 自加3后自赋值
  • 自增,自减:
  • let var+=1
  • let var++
  • let var-=1
  • let var--

1.8.12 逻辑运算

  • 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,第二个必须要参与运算
  • 异或:^
    • 异或的两个值,相同为假0,不同为真1

1.8.13 条件测试

  • 判断某需求是否满足,需要由测试机制来实现
  • Note:专用的测试表达式需要由测试命令辅助完成测试过程
  • 评估布尔声明,以便用在条件性执行中
    • 若真,则返回0
    • 若假,则返回1

1.8.14 测试命令

  • test EXPRESSION
  • [ EXPRESSION ]
  • [[ EXPRESSION ]]
  • 注意:EXPRESSION前后必须有空白字符

1.8.15 bash的数值测试

  • 数值测试:
    • -gt 是否大于
    • -ge 是否大于等于
    • -eq 是否等于
    • -ne 是否不等于
    • -lt 是否小于
    • -le 是否小于等于

1.8.16 bash的字符串测试

  • 字符串测试:
    • = 是否等于

    • > ascii码是否大于ascii码

    • < 是否小于

    • != 是否不等于

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

    • 注意: 此表达式一般用于[[]]中;扩展的正则表达式,右侧的PATTERN不加引号

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

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

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

[root@CentOS7 ~]# var=abcdef;[[ "$var" = abc* ]] && echo 1 || echo 0
1 ## [[  = ]] 支持通配符
[root@CentOS7 ~]# var=abcdef;[[ "$var" = "abc*" ]] && echo 1 || echo 0
0  ## 引号引起来的都视为是字符串
[root@CentOS7 ~]# filename=a.conf;[[ "$filename" =~ \.conf ]] && echo 1 || echo 0
1 ## 正则表达式不加引号

1.8.17 Bash的文件测试

1.8.17.1 文件存在性测试

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

1.8.17.2 文件类别测试

  • -b FILE:是否存在且为块设备文件
  • -c FILE:是否存在且为字符设备文件
  • -d FILE:是否存在且为目录文件
  • -f FILE:是否存在且为普通文件
  • -h FILE 或 -L FILE:存在且为符号链接文件
  • -p FILE:是否存在且为命名管道文件
  • -S FILE:是否存在且为套接字文件

1.8.17.2 Bash的文件权限测试

  • -r FILE:是否存在且可读
  • -w FILE: 是否存在且可写
  • -x FILE: 是否存在且可执行

1.8.17.3 文件特殊权限测试:

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

1.8.17.4 Bash的文件属性测试

  • 文件大小测试:
  • -s FILE: 是否存在且非空

1.8.17.5 文件是否打开:

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

1.8.17.6 Bash的文件属性测试

  • 双目测试:
    • FILE1 -ef FILE2: FILE1是否是FILE2的硬链接
    • FILE1 -nt FILE2: FILE1是否新于FILE2(mtime) - FILE1 -ot FILE2: FILE1是否旧于FILE2

1.8.17.7 Bash的组合测试条件

  • 第一种方式:
    • COMMAND1 && COMMAND2 并且
    • COMMAND1 || COMMAND2 或者
    • ! COMMAND 非
    • 如:[[ -r FILE ]] && [[ -w FILE ]]
  • 第二种方式:
    • EXPRESSION1 -a EXPRESSION2 并且
    • EXPRESSION1 -o EXPRESSION2 或者
    • ! EXPRESSION 非
    • 必须使用测试命令进行
    • 示例:
[root@CentOS7 ~]# [ -z "$HOSTNAME" -o $HOSTNAME == "CentOS7.5.zhu.com" ] && echo 1 || echo 0
1
[root@CentOS7 ~]#[ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab
[root@CentOS7 ~]#[ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab
# /etc/fstab
# Created by anaconda on Wed Jul 18 17:26:27 2018

1.8.18 使用read命令来接受输入

  • 使用read来把输入值分配给一个或多个shell变量
    • -p 指定要显示的提示
    • -s 静默输入,一般用于密码
    • -n N 指定输入的字符长度N
    • -d '字符' 输入结束符
    • -t N TIMEOUT为N秒
  • read 从标准输入中读取值,给每个单词分配一个变量 所有剩余单词都被分配给最后一个变量
  • read -p "Enter a filename:" FILE

1.8.19 bash的配置文件

  • 按生效范围划分,存在两类:
  • 全局配置: /etc/profile /etc/profile.d/*.sh /etc/bashrc
  • 个人配置: ~/.bash_profile ~/.bashrc

1.8.20 shell登录两种方式

  • 交互式登录:
  • (1)直接通过终端输入账号密码登录
  • (2)使用“su - UserName” 切换的用户
  • 执行顺序:/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc
  • 非交互式登录:
  • (1)su UserName
  • (2)图形界面下打开的终端
  • (3)执行脚本
  • (4)任何其它的bash实例
  • 执行顺序: ~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh

1.8.20.1 Profile类

  • profile类:为交互式登录的shell提供配置
    • 全局:/etc/profile, /etc/profile.d/*.sh

    • 个人:~/.bash_profile

    • 功用:

    • (1)用于定义环境变量

    • (2) 运行命令或脚本

1.8.20.2 Bashrc类

  • bashrc类:为非交互式和交互式登录的shell提供配置
    • 全局:/etc/bashrc
    • 个人:~/.bashrc
    • 功用:
    • (1) 定义命令别名和函数
    • (2) 定义本地变量

编辑配置文件生效

  • 修改profile和bashrc文件后需生效
  • 两种方法:
    • 1重新启动shell进程
    • 2 . 或source
      例: . ~/.bashrc
  • 让任意一个目录下的具有执行权限的脚本不用输入路径就可以执行。
[root@CentOS7 scripts]# cat /etc/profile.d/zhu.sh
PATH=.:$PATH
[root@CentOS7 scripts]# . /etc/profile.d/zhu.sh
[root@CentOS7 scripts]# yesorno.sh
please input yes or no:y
Your answer is YES.
[root@CentOS7 scripts]# echo $PATH
.:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
tips:为了安全考虑,在生产中不建议这么做 

1.8.21 Bash 退出任务

  • 保存在~/.bash_logout文件中(用户)
  • 在退出登录shell时运行
  • 用于创建自动备份
  • 清除临时文件

1.8.22 $-变量

  • h:hashall,打开这个选项后,Shell 会将命令所在的路径hash下来,避免每次都要查询。通过set +h将h选项关闭
  • i:interactive-comments,包含这个选项说明当前的 shell 是一个交互式的 shell。所谓的交互式shell,在脚本中,i选项是关闭的(cat /etc/profile.d/vte.sh)
  • m:monitor,打开监控模式,就可以通过Job control来控制进程的停止、继 续,后台或者前台执行等。
  • B:braceexpand,大括号扩展
  • H:history,H选项打开,可以展开历史列表中的命令,可以通过!感叹号来完 成,例如“!!”返回上最近的一个历史命令,“!n”返回第 n 个历史命令
posted @ 2019-09-11 14:16  马老师的笨学生  阅读(239)  评论(0编辑  收藏  举报