08-shell脚本编程基础
08-shell脚本编程基础

08-shell脚本编程基础

1.bash特性及bash脚本编程初步

image-20230530102842433

终端:附着在终端的接口程序

  • GUI: KDE, GNome, Xfce
  • CLI: /etc/shells

bash的特性:

  • 命令行展开: ~, {}

  • 命令别名:alias, unlias

  • 命令历史:history

  • 文件名通配:glob

  • 快捷键: Ctrl + a, e, u, k, l

  • 命令补全: $PATH

  • 路径补全

1.bash特性之:命令哈希hash

缓存此前命令查找的结果: key-value

key: 搜索键

value:值

hash命令:

hash:列出

hash -d COMMAND: 删除

hash -r : 清空

[lemon@VM-4-10-centos ~]$ help hash
hash: hash [-lr] [-p 路径名] [-dt] [名称 ...]
    记住或显示程序位置。

    确定并记住每一个给定 NAME 名称的命令的完整路径。如果
    不提供参数,则显示已经记住的命令的信息。

    选项:
      -d                忘记每一个已经记住的命令的位置 # 删除指定值
      -l                以可作为输入重用的格式显示
      -p pathname       使用 pathname 路径作为 NAME 命令的全路径
      -r                忘记所有记住的位置  # 清空哈希表
      -t                打印记住的每一个 NAME 名称的位置,如果指定了多个
                NAME 名称,则每个位置前面会加上相应的 NAME 名称

    参数:
      NAME              每个 NAME 名称会在 $PATH 路径变量中被搜索,并
                且添加到记住的命令的列表中。

    退出状态:
    返回成功,除非 NAME 命令没有找到或者使用了无效的选项。

测试:

[rhino@rhino010 lxc]$ rm -rf test
[rhino@rhino010 lxc]$ mkdir test
[rhino@rhino010 lxc]$ hash
hits    command
   1    /usr/bin/tty
   1    /usr/bin/install
   1    /usr/sbin/ifconfig
   2    /usr/bin/rm
   1    /usr/bin/who
   3    /usr/bin/mkdir
   1    /usr/bin/ls
[rhino@rhino010 lxc]$ hash -d ls
[rhino@rhino010 lxc]$ hash
hits    command
   1    /usr/bin/tty
   1    /usr/bin/install
   1    /usr/sbin/ifconfig
   2    /usr/bin/rm
   1    /usr/bin/who
   3    /usr/bin/mkdir
[rhino@rhino010 lxc]$ hash -r
[rhino@rhino010 lxc]$ hash
hash: hash table empty

2.bash特性之:变量

  • 程序:指令+数据

    • 指令:由程序文件提供

    • 数据:IO设备(通过键盘输入等)、文件、管道

  • 程序:算法+数据结构

  • 变量赋值:name=value

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

    • 编程语言:
    • 强类型变量: C语言等
    • 弱类型变量:bash
      • bash把所有变量统统视作字符型
      • bash中的变量无需事先声明,相当于把声明和复制过程同时实现(python也无需声明,但还是算强类型变量,毕竟不能执行1+'2'
  • 变量替换:把变量名出现的位置转换为其所指向的内存空间中数据的过程

  • 变量引用: ${var_name}, $var_name

  • 变量名命名方式:所有编程语言变量命名基本上规范一致,只能包含数字、字母、下划线,不能以数字开头

  • bash变量类型:

    • 本地变量:作用域仅为当前shell进程
    • 环境变量:作用域为当前shell进程及其子进程(再键入一次bash则进入子shell进程,新开的终端是不行的,可以who查看终端情况)
    • 局部变量:作用域仅为某代码片段(函数上下文)
    • 未知参数变量:就是向执行脚本shell进程传递的参数
    • 特殊变量:通常是shell内置的有特殊公用的变量
    • $?保存上一个命令的执行状态结果(0表示成功,1-255表示失败)
  • bash变量赋值方式:

    • 本地变量赋值:name=value

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

      • "":变量名会替换为其值
      • '':变量名不会替换为其值
    • 查看变量:set

    • 撤销变量:unset name 注意,此处非变量引用

    • 环境变量:

    • 变量赋值(四种方式):

      • export name=value

      • name = value
        export name
      • declare -x name=value

      • name=value
        declare -x name
    • 变量引用:${name}, $name,注意,bash内嵌了许多环境变量(通常为全大写字符,如PATH, HISTFILE,HISTZISE,HISTFILESIZE,HISTCONTROL,SHELL,HOME,UID,OWD,OLDPWD),用于定义bash的工作环境

    • 查看环境变量

      • printenv
      • declare -x
      • env
      • export
    • 撤销环境变量:unset name

    • 只读变量:无法重新赋值,并且不支持撤销:存活时间为当前shell进程的生命周期,岁shell进程终止而终止

    • declare -r name

    • readonly name

3. bash特性之:多命令执行

  • ~]# COMMAND1; COMMAND2; COMMAND3;

  • 逻辑运算:

    • 运算数:

    • 真(true, yes, on, 1)

    • 假(false, no, off, 0)

    • 与:&&可用于乘法

    1 && 1 = 1
    0 && 1 = 0
    0 && 0 = 0
    1 && 0 = 0
    • 或:||
    1 || 1 = 1
    0 || 1 = 1
    0 || 0 = 0
    1 || 0 = 1
    • 非:!
    !1 = 0
    !0 = 1
    • 异或:
  • 短路法则:

    • ~]# COMMAND1 && COMMAND2

    COMMAND1为假,则COMMAND2不会再执行;否则必须执行

    • ~]# COMMAND1 || COMMAND2

    COMMAND1为真,则COMMAND2不会再执行;否则必须执行

    • 示例:查看某用户id,如果查看失败(即不存在该用户),那么创建之

    ~]# id $username || useradd $username

2.shell脚本编程

1.概述

编程语言的分类:根据运行方式

  • 编译运行:源代码 --> 编译器 ( 编译)-> 程序文件;
  • 解释运行:源代码 -> 运行时启动解释器,由解释器边解释边运行

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

  • shell脚本编程:利用系统上的命令及编程组件进行编程;
  • 完整编程:利用库或给程组件进行编程:

编程模型:过程式编程语言,面向对象的编程语言

  • 过程式:以指令为中心来组织代码,数据是服务于代码;

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

    代表:C,bash

  • 对象式:以数据为中心来组织代码,围绕数据来组织指令;

    • 类(class):实例化对象,method;

代表: Java,C++,Python
shell脚本编程:过程式编程,解释运行,依赖于外部程序文件运行;

shell脚本是什么:命令的堆砌,自上而下执行;但由于很多命令不具有幂等性,需要用程序逻辑来判断运行条件是否满足,以避免其运行中发生错误。

2.如何编写

脚本文件的第一行,顶格:给出shebang,解释器路径,用于指明解释执行当前脚本的解释器程序文件

常见的解释器:

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

文本编辑器:nano

行编辑器:sed

全屏幕编辑器:nano, vi, vim

尝试用nano编写一个shell脚本:

nano myfirst.sh

看见大概长这样:

image-20230530160415602

使用Ctrl+X退出,Ctrl+O写入

执行:

[root@VM-4-10-centos ~]# sh myfirst.sh
更改用户 user3 的密码 。
passwd:所有的身份验证令牌已经成功更新。
/tmp/test.uFOOSC

# 或者使用路径,./myfirst.sh, /root/myfirst.sh, bash myfirst.sh

刚刚的shell脚本中,如果再次执行,创建会失败,但是后两步并不会终止

如果想要判断用户存在,若存在则不再创建,只执行后续的改密码等操作,可以使用||与,COMMAND1成功则不再执行COMMAND2

#!/bin/bash
# 添加用户并设置密码
id user3 || useradd user3
echo "user3" | passwd --stdin user3

mktemp -d /tmp/test.XXXXXX
[root@VM-4-10-centos ~]# sh myfirst.sh
uid=1005(user3) gid=1005(user3) 组=1005(user3)
更改用户 user3 的密码 。
passwd:所有的身份验证令牌已经成功更新。
/tmp/test.t6oD2U

3.执行脚本的方法

  1. 赋予执行权限,并直接运行此程序文件:

    chmod +x /PATH/TO/SCRIPT_FILE
    /PATH/TO/SCRIPT_FILE
  2. 直接运行解释器,将脚本以命令行参数传递给解释器程序

    bash /PATH/TO/SCRIPT_FILE
    sh /PATH/TO/SCRIPT_FILE

4.简单练习

练习1:显示/etc目录下所有以大写P或者小写p开头的文件或目录本身;

#!/bin/bash
ll /etc/P* # 大写
ll /etc/p* # 小写
ll /etc/[Pp]* # 不区分大小写

练习2:显示/var目录下的所有文件或者目录本身,并将显示结果中的小写字母转换为大写后显示;

#!/bin/bash
ls -d /var/* | tr 'z-z' 'A-Z'

练习3:创建临时文件/tem/myfile.XXXX;

#!/bin/bash
mkdir /tem/myfile.XXXX

综合

#!/bin/bash
echo "Show some under /etc"
ls -d /etc/[pP]*
echo "Traslate lower to upper"
ls -d /var/*tr 'a-z''A-Z'
echo "Create a temp file"
mktemp /tmp/myfile.XXXX

5.bash的配置文件

1. 配置文件类型

配置文件主要分为两类:

profile类:为交互式登录的shelli进程提供配置

bashrc类:为非交互式登录的shelli进程提供配置

登录类型:

  • 交互式登录shelli进程:
    直接通过某终端输入账号和密码后登录打开的shelli进程:
    使用su命令:Su - USERNAME,或者使用su -I USERNAME执行的登录切换:

  • 非交互式登录shel进程
    su USERNAME执行的登录切换:
    图形界面下打开的终端:
    运行脚本

profile类:

  • 全局:对所有用户生效

    /etc/profile
    /etc/profild.d/*.sh
  • 用户个人:仅对当前用户有效

    ~/.bash_profile

  • 功用:

    1. 用于定义环境变量
    2. 运行命令或脚本

bashrc类:

  • 全局:

    /etc/bashrc

  • 用户个人:

    ~/.bashrc

  • 功用:

    1. 定义本地变量
    2. 定义命令别名

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

2.shell读取配置顺序

  • 交互式登录shell进程:
    /etc/profile-->/etc/profile.d/*-->~/.bash_profile ->~/.bashrc-->/etc/bashrc
  • 非交互式登录shell:进程:
    -/.bashrc-->/etc/bashrc-->/etc/profile.d/*

命令行中定义的特性,例如变量和别名作用域为当前shl进程的生命周期;
配置文件定义的特性,只对随后新启动的shell进程有效:
让通过配置文件定义的特性立即生效:

  1. 通过命令行重复定义一次:

  2. 让shelli进程重读配置文件:

    source /PATH/FROM/CONF_FILE
    /PATH/FROM/CONF_FILE

3.实验

别名测试:将clear写到配置文件中别名为cls

直接敲cls是无该命令的ll,将clear别名成cls

[lemon@VM-4-10-centos ~]$ cls
-bash: cls: 未找到命令
[lemon@VM-4-10-centos ~]$ vim .bashrc

添加alias cls=clear:

[lemon@VM-4-10-centos ~]$ cat .bashrc
# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi
VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
export WORKON_HOME=$HOME/.virtualenvs
source /home/lemon/.local/bin/virtualenvwrapper.sh

alias cls=clear
# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=

# User specific aliases and functions

再执行cls,就OK了。实测有效,但是root是执行不了的,全局的话去修改/etc/profile

比如写个欢迎登陆的全局变量脚本:

[root@VM-4-10-centos ~]# vim /etc/profile.d/welcome.sh
[root@VM-4-10-centos ~]# cat /etc/profile.d/welcome.sh
echo "天上人间理疗会所全体佳丽,欢迎贵宾光临!"

image-20230530174614977

也可以用重定向写:echo 'echo "welcome!"' > /etc/profile.d/welcome.sh


export:导出环境变量

发表回复

您的电子邮箱地址不会被公开。