Shell脚本

446 阅读8分钟

基础

  • Shell是一个命令行解释器,它为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序
  • 用户可以用Shell来启动、挂起、停止或者编写一些程序
  • Shell还是一个功能相当强大的编程语言、易编写、易调试、灵活性较强
  • Shell是解释执行的脚步语言,在Shell中可以直接调用Linux系统命令

名词

  1. usr目录: Unix System Resource,放系统文件

  2. $()$(())的区别一个小括号表示获取命令的值两个小括号表示计算一个算术表达式

    # 一个小括号
    $ echo 1 > 1.txt
    $ x=$(cat 1.txt)
    $ echo $x  # 输出1
    
    # 两个小括号
    $ a=10
    $ b=11
    $ c=$((a+b))
    $ echo $c  # 输出21
    
  3. $? : 返回上一条命令的返回值

  4. Linux 三个标准输入和输出

    0 代表标准输入 键盘

    1 代表标准输出 控制台 >

    2 代表错误输出 控制台

  5. httpdapache 关系,简单理解就是apache2以上的版本改称为httpd

  6. ' ' 和 " " 和 ''' '''的区别

    $ name = hcc
    $ echo '$name'  => 输出 $name 字符串
    $ ehco "$name"  => 输出 hcc  等价于 "${name}"
    # 多行执行命令
    '''
       echo 'hcc'
       echo  "${name}"
    '''
    
    

支持的Shell脚本

cat /etc/shells

  1. echo

    #!/bin/bash 
    $ echo hello
    
  2. alias

  3. history

  4. 重定向

    1. >  覆盖
    2. >> 追加
    
    # 错误的重定向
    $ cat xx.txt > error.log 2>&1
    # 追加 &代表引用
    命令 > 文件 2>>&1
    
  5. 管道符号

  6. 通配符([a-z], [abc])

  7. 其他符号

    1.不能有空格 2.双引号可以识别变量,单引号是字符串表示

    符号 作用
    ''(单引号) 在单引号中所有的特殊符号,如$和`都没有特殊含义
    ""(双引号) 在双引号里特殊符号都没有特殊含义,但是 和`和\例外(引用和转义)
    ``(反引号) 扩起来的是系统命令
    $() 和反引号功能一样
    $ 用于调用变量的值
    \ 转义符号
  8. awk: 提取文本中的字段

  9. sed: 修改文件,相当于一个记事本,类似vi

  10. read : 从标准输入读取数值

  11. scp(secure copy): 服务器和客户端进行拷贝

一. 变量

  1. 变量的分类

    • 字符串
    • 整型
    • 浮点型
    • 日期型
  2. 用户自定义变量(都是字符串)

    # 局部变量
    name=hcc
    echo $name
    
    # 查看已经定义的变量
    set | grep name
    
  3. 取变量的值

    • 双引号内部通过:   `"xxx"`
  4. 查看变量和删除变量

    set命令查看系统中已经生成的变量,包括自定义变量和系统变量

    unset 删除变量

    # 查看已经定义的变量
    $ set | grep name
    $ unset name 
    
  5. 环境变量

    • 环境变量是全局变量,而自定义变量是局部变量
    • 自定义变量会在当前的Shell中生效,而环境变量会在当前的Shell以及其子Shell中生效
    • 这种变量主要是保存的是和系统操作环境相关的数据
    • 变量可以自定义,但是对系统生效的环境变量和变量作用是固定的
    # 自定义环境变量  export(不加export就是局部变量)
    $ export 变量名=变量值
    $ export envname=prod
    
    # 查看环境变量
    $ env
    
  6. 位置参数变量

    位置参数变量 作用
    $n n为数字,$0代表命令本身,$1-9代表第1到第9个参数,10以上的参数就需要用大括号包含,如{10}
    $* 代表命令中所有的参数,$*把所有的参数当成一个整体(一个)
    $@ 也代表命令中所有的参数,不过$@把每个参数进行区分(多个)
    $# 代表参数的个数

二、运算符

  • Shell是弱类型并且默认的是字符串类型

1. declare 命令

  • 用于声明变量类型

  • declare [+/-] [选项] 变量名

    选项 含义
    - 给变量设定类型属性
    + 取消变量的类型属性
    -a 将变量声明为数组类型
    -i 将变量声明为整数型(interger)
    -x 将变量声明为环境变量 (export也可以)
    -r 将变量声明为只读变量
    -p 显示指定变量的被声明的类型

2. 数组

$ name[0]=zhangsan
$ name[1]=lisi
#不写数组下标,默认获取第一项
$ echo ${names}

$ echo ${names[1]}

# 获取数组全部项
$ echo ${name[*]}

$ declare -a names;

三、环境变量配置文件

3.1. source命令

  • 修改完配置文件后,必须注销重新登录才能生效,使用source命令可以不用重新登录
  • source 配置文件

3.2 环境变量配置文件简介

  • PATH、HISTSIZE、PS1、HOSTNAME等环境变量写入对应的环境变量配置文件

  • 环境变量配置文件中主要是定义地系统操作环境生效的系统默认环境变量,如PATH等 此下文件是登录时起作用的环境变量

      | 路径                | 说明               |
      | ------------------- | ------------------ |
      | /etc/profile        |                    |
      | /etc/profile.d/*.sh |                    |
      | /etc/bashrc         |                    |
      | ~/.bashrc           | 只会对当前用户生效 |
      | ~/.bash_profile     | 只会对当前用户生效 |
    

linux启动的变量配置.png

3.3 环境变量配置文件的功能

  • /etc/profile 修改系统环境变量

    | 变量名              | 含义     |
    | ------------------- | -------- |
    | USER                | 用户名   |
    | LOGNAME             | 登录名   |
    | MAIL                | 邮箱地址 |
    | PATH                | 查找路径 |
    | HOSTNAME            | 主机名   |
    | umask               | 权限掩码 |
    | /etc/profile.d/*.sh |          |
    
  • ~/.bash_profile

    1. 全局修改PATH 路径
    2. 调用~/.bashrc
  • ~/.bashrc

    1. 配置alias (修改别名在这里)
    2. 调用/etc/bashrc
  • /etc/bashrc

    1. PS1: 登录提示符在这里修改
    2. 修改PATH变量
    3. umask : 权限掩码
    4. 调用/etc/profile.d/*.sh文件脚本

四、条件判断

1. 按照文件类型进行判断

选项 含义
-d 文件是否存在并且是目录
-e 文件是否存在
-f 文件是否存在并且是普通文件
-b(block) 文件是否存在并且是块设备文件
-c(char) 文件是否存在并且是字符设备文件
-L 文件是否存在并且是链接文件
-p(pipe) 文件是否存在并且是管道文件
-s 文件是否存在并且是否为非空
-S(Socker) 文件是否存在并且是套接字文件
$ test -e 1.txt
$ echo $?

# [] 2边有一个空格 
$ [ -e hello.txt ]&& echo 'yes' || echo 'no'

2. 按照文件的权限进行判定

选项 含义
-r 文件是否存在,并且可读
-w 文件是否存在,并且可写
-x 文件是否存在,并且可执行
$ [ -r hello.txt ]&& echo 'yes' || echo 'no'

3. 比较2个文件的修改时间

选项 含义
文件1 -nt 文件2 判断文件1的修改时间是否比文件2的新(new than)
文件1 -ot 文件2 判定文件1的修改时间是否比文件2的旧 (old than)
文件1 -ef 文件2 判断文件1和文件2的inode号是否一致,可用于判定硬链接(equal file)

4. 比较2个整数

选项 含义
整数1 -eq 整数2 判定整数1是否和整数2相等
整数1 -ne 整数2 是否不相等
整数1 -gt 整数2 整数1是否大于整数2
整数1 -lt 整数2 整数1是否小于整数2
整数1 -ge 整数2 整数1是否大于等于整数2
整数1 -le 整数2 整数1是否小于等于整数2

5. 字符串的判断

选项 含义
-z 字符串 判断字符串是否为空
-n 字符串 判断字符串是否为非空
字符串1 == 字符串2 判断字符串1是否和字符串2相等
字符串1 != 字符串2 判断字符串1是否和字符串2不相等
$ name=hcc
$ [ -z name] && echo 'yes' || echo 'no'

五、条件判断

  • if语句使用fi结尾
  • [ 条件判断式 ] 就是使用test命令进行判断,所以中括号和条件判断式之间必须有空格
  • then 后面跟符合条件之后的执行的程序,可以放在[]之后,用;分隔,也可以换行不用;

5.1 单分支if语句

  1. 语法

    if [ 条件判断 ];then
    	代码体
    fi  
    
    if [ 条件判断 ]
    then 
    	代码体
    fi  
    
    if [ 2 -gt 1 ];then echo bigger;fi
    
    # 判断是不是root用户 isRoot.sh
    #!/bin/bash
    currentName=$(whoami)
    if [ $currentName == 'root' ]
    then
      echo '是root用户'
    fi
    

5.2 双分支if语句

  1. 语法

    if [ 条件判断 ]
    then 
    	代码体1
    else 
    	代码体2
    fi  
    
    # 判断是否是目录
    #!/bin/bash
    read -t 10 -p "请输入目录或者文件:" name
    if [ -d "$name" ]
    then
      echo "$name 输入的是目录"
    else
      echo "$name 不是目录,可能是文件"
    fi
    

5.3 多分支if语句

  1. 语法

    if [ 条件判断 ]
    then 
    	代码体1
    elif [ 条件判断 ]
    then
    	代码体2
    elif [ 条件判断 ]
    then
    	代码体3
    else 
    	代码体4
    fi  
    
    # 判断分数
    #!/bin/bash
    read -t 10 -p "请输入一个分数:" score
    if [ "$score" -ge 90 ]
    then
      echo "$score 是优秀"
    elif [ "$score" -ge 80 ]
    then
      echo "$socre 是中等"
    elif [ "$score" -ge 60 ]
    then
      echo "$score 是及格"
    else
      echo "不及格"
    fi
    

5.4 case语句

  1. 语法

    case 变量名 in
    值1)
    	代码块1
     ;;
    值2)
     代码块2
    ;;
    *)
     代码块3
    ;;
    esac
    
    #!/bin/bash
    read -t 10 -p "请输入(A/B/C/*)中的一个等级:" -n 1 level
    echo -e "\n"
    case "$level" in
    "A")
      echo "优秀"
    ;;
    "B")
      echo "中等"
    ;;
    "C")
      echo "及格"
    ;;
    *)
      echo "不及格"
    ;;
    esac
    

七、函数

  • Linux Shell 可以用户定义函数,然后再Shell脚本中可以随便调用
  • 可以带function fun() {} 定义,也可以直接fun() {}, 不带任何参数
  • 调用函数不需要添加()

1. 格式

[ function ] funcname () {
	action;
	[return int]
}
start() {
	echo start
}
start

#!/bin/bash
start() {
	echo start()
}
start

2. 返回值

  • 默认返回return的值

    > sum() {
    > r=$(($1+$2))
    > return $r
    > }
    $ sum 2 3
    $ echo $?  # 输出5
    

3. 参数说明

参数处理 说明
$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数
$@ 与$*相同,但是使用时加引号,并在引号中返回每个参数
? 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$- 显示Shell使用的当前选项,与set命令功能相同
$? 显示最后命令的退出状态,0表示没有错误,其他任何值表明有错误

八、软件包管理

8.1 软件包分类

  • 源码包(需要经过编译,把人所编写的源代码编译成机器语言才能运行)

  • 二进制包rpm(把源代码包经过编译生成0/1二进制,PRM包、系统默认的安装包)

    $ rpm -ivh 包名
    
  • 脚本安装包(就是把复杂的安装过程写成脚本,可以一键安装,本质上安装的还是源代码包和二进制包)

8.2 yum在线管理包

  • yum = Yellow dog Updater, 解决包的依赖性问题,他是rpm包的在线管理命令

  • 将所有软装名放到官方的服务器上,当进行YUM在线安装时,可以自动解决依赖性问题

  • /etc/yum.repos.d/ 资源库

    1. CentOS-Base.repo

    2. CentOS-Debuginfo.repo

    3. CentOS-Media.repo

    4. CentOS-Vault.repo

      命令 含义
      yum list 查询所有可用的软件包列表
      yum search 关键词 搜索服务器上所有和关键词相关的包
      yum -y install 包名 -y 自动回答yes install 安装
      yum -y update 包名 升级软件包
      yum -y remove 包名 remove 卸载有依赖性,所以尽量不要卸载
      yum grouplist 列出所有可用的软件组列表

8.3 源码包安装

  • RPM包安装位置是由软件包作者决定的,我们不需要指定安装位置

  • RPM包安装的服务可用使用系统服务管理命令(service systemctl)来管理

    $ systemctl start httpd.service
    
  • 源码包安装在指定的位置当中,一般是/usr/local/软件名

  • 源码包安装的服务不能被服务器命令管理,因为没有安装到默认路径中,所以只能用绝对路径进行服务的管理

8.3.1 安装准备
  1. 安装C语言编译器

    # 使用c语言编译器把C语言编译成二进制源代码
    $ yum install -y gcc
    
  2. 安装注意事项

    • 源码包一般放在/usr/local/src目录下
    • 软件的安装位置/usr/local, 相当于c盘的program files目录
    • 如何确定安装过程是否正常 (安装过程能正常中止,出现error提示)
  3. 下载源文件包并解压,进入解压目录

    $ wget https://nodejs.org/dist/v12.14.1/node-v12.14.1.tar.gz
    $ tar -xzvf node-v12.14.1.tar.gz
    $ cd node-v12.14.1
    
  4. configure配置

    软件配置与检查

    • 定义需要的功能选项
    • 检察系统环境是否符合安装要求
    • 把定义好的功能选项和检查系统环境的信息都写入Makefile文件中,用于后续的编辑
    # prefix 指定安装后的目录
    ./configure --prefix=/usr/local/node 
    
    # 执行了之后会生成一个Makefile文件
    
  5. 编译和安装

    • 把源码编译成二进制文件 make , 如果报错执行make clean 进行清理
    • 通过make install 安装
    $ make
    $ make install
    

九、进程

  • 进程是正在执行的一个程序或命令,每一个进程都是一个运行的实体,都有自己的地址空间并且用一定的系统资源
  • 进程就是正在运行的某个程序
  • 一个进程中至少有一个进程,有些服务是单进程,单线程(node.js),有些服务是多进程的,有些是多线程(php)

9.1 进程的查看命令(ps

参数 含义
-a 显示一个终端的所有进程
-u 显示进程的归属用户及内存的使用情况
-x 显示没有控制终端的进程
ps -aux 常用这个命令查看进程

9.2 进程的查看命令(top

$ top -b -n 1 > top.txt
选项 含义
-b 使用批处理模式输出,一般和-n配合使用
-n 次数,指定top命令执行的次数,一般和-b配合使用
-d 秒数,指定top命令每隔几秒更新。默认是3秒

9.3 杀死进程(kill

  • kill -l 查看可用的进程信号

      | 信号代码 | 信号名称 | 说明                                                         | 实例                     |
      | -------- | -------- | ------------------------------------------------------------ | ------------------------ |
      | 1        | SIGHUP   | 该信号让进程立即关闭,然后重写读取配置文件后重启(平滑重启) | kill -1 -HUP 进程号      |
      | 2        | SIGINT   | 程序终止信号,用于关闭前台进程,相当于`ctrl+c`               | 充容关闭,进程还可以忽略 |
      | 9        | SIGKILL  | 用来立刻结束程序的运行,本信号不能阻塞、处理和忽略,一般用于强制中止 |                          |
      | 15       | SIGTEAM  | 正常结束进程的信号,kill命令的默认信号,如果不能正常中止,才会尝试SIGKILL信号 |                          |
    
  • 杀死进程方式

    1. 杀死单进程
    $kill -9 进程号
    
    1. 按照进程名称杀死
    $ killall [选项][信号] 进程名 
    -i 交互式,询问是否杀死某个进程
    -l 进程名忽略大小写
    
    #eg
    $ killall httpd
    

9.4 后台进程(& ctrl + z

  • 工作管理就是指的是单个登录终端中同时管理多个工作的行为
  • 有时候有些命令会卡住我们的操作界面,我们就需要把它放入后台,比如拷贝大型文件
  • 当前的登录终端只能管理当前终端的工作,而不能管理其他终端工作
  • 放入后台的命令必须是还要持续一段时间的,这样我们才能去捕捉和操作这个动作
  • 放入后台的命令不能和前台用户有交互或者前台输入,否则放入后台只能暂停,而不会执行
  1. 把进程放入后台
    • & 在命令后面加,可以把命令放入后台,并在后台执行
    • ctrl+z 把工作放在后台暂停
  2. 查看后台的工作
    • jobs -l 显示工作的PID
  3. 恢复到前台
    • fg

9.5 系统资源查看

  1. vmstat

    • 监控系统资源使用状态
    • vmstat [刷新延时 刷新次数]
    procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
     r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
     3  0      0  78456  72124 991132    0    0    16    28    3    3  1  1 99  0  0
    
    • procs进程信息字段

      分类 参数 含义
      procs r 等待运行的进程数,数量越大,系统就越繁忙
      procs b 不可被唤醒的进程数量,数量越大,系统越繁忙
    • memory(内存信息字段)

      分类 参数 含义 (单位kb)
      memory swpd 使用的swap空间的大
      memory free 空闲的内存容量
      memory buff 缓冲的内存容量
      memory cache 缓存的内存容量

十、系统定时任务和网络

  • 有些任务比如备份数据库等操作需要在系统空闲的时候执行

10.1 at命令 (一次性任务,使用比较少)

  1. $ at [选项] 时间
  2. atq 查询定时任务
  3. atrm 删除任务
  4. /etc/at.deny 哪些用户不能使用at 命令 /etc/at.allow 那些用户可以使用at
# 选项
# -m  当at工作完成后,无论是否命令有输出,都用email通知执行at命令的用户
# -c  工作号,显示该at工作的实际内容

# 例子
$ at 20:15  然后再按ctrl + d
$ at now + 3 minutes

10.2 域名解析命令

  • nslookup [主机名或IP] (nameServer)
  • 进行域名与IP地址解析
  • 查看本机的DNS服务器
$ nslookup www.baidu.com

Address: 39.156.69.79

10.3 网络测试命令

  1. ping [选项] ip或域名 测试指定IP或域名的网络状况
  2. traceroute [选项] IP或域名 路由跟踪命令
  3. wget 地址 下载命令
$ ping www.baidu.com -c 3

$ traceroute www.baidu.com	

10.4 搭建ftp服务器

  1. 查询s是否已经安装了vsftpd服务

    $ rpm -q vsftpd
    
  2. 安装vsftpd

    $ yum install -y vsftpd
    
  3. 启动服务

    $ systemctl start vsftpd
    
  4. 修改vsftpd配置文件

    • vi /etc/vsftpd/vsftpd.conf

      anonymous_enable=YES  是否允许匿名用户登录
      local_enable=YES    允许本地用户登录
      write_enable=YES    是否可以写入
      
      
      chroot_local_user=YES    是否将所有用户限制在主目录,YES为启用
      chroot_list_enable=YES   是否启动限制用户的名单
      chroot_list_file=/etc/vsftpd/chroot_list    是否限制在主目录下的用户名单
      
  5. 设置用户可以访问home的文件夹

    $ getsebool -a|grep ftp  # 查看selinux配置
    $ setsebool -P ftp_home_dir 1 # 更改配置(-P  是开机自动使用,无需每次开机都输入该命令)
    $ systemctl restart vsftpd # 重启vsftpd
    
    $ vi /etc/selinux/config
    SELINUX=disabled
    

10.5 远程登录

  1. ssh 用户名@ip 远程管理指定的Linux服务器

    $ ssh root@122.51.225.116
    
    The authenticity of host '122.51.225.116 (122.51.225.116)' can't be established.
    ECDSA key fingerprint is SHA256:P4L/OyA7aehEqXpgaYZU58FJ7TTqLVetyCwFwab0cDE.
    Are you sure you want to continue connecting (yes/no)? yes
    Warning: Permanently added '122.51.225.116' (ECDSA) to the list of known hosts.
    
  2. 查看已经存放的公钥 /root/.ssh/known_hosts

    122.51.225.116 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMjKRqQf1wBW1+2CIwI5GNkahg4giWJFbeIvyFMc8h8KQAly1msWjtF39Ib9rYRdqbUpr9HG4cIS1ktwIBi1Wk3=