shell基础

50 篇文章 4 订阅
36 篇文章 11 订阅
本文详细介绍了Shell脚本的基础知识,包括脚本介绍、学习优势、应用场景、内容及技巧。深入讲解了变量、运算、格式化输出、用户交互等核心概念,并通过数据磁盘初始化、用户登录系统等实战案例,演示了Shell脚本的实际运用。此外,还涵盖了逻辑运算、文件判断等高级操作,帮助读者全面掌握Shell脚本的编写和应用。
摘要由CSDN通过智能技术生成

目录

shell脚本介绍

一、shell脚本是什么

通过shell语言将完成一个任务的所有代码写入一个文件,并给执行权限。

二、为什么要学shell,而不是其他计算机语言

  • 上手快
  • 入门简单
  • 学习周期短

三、学习这门课程的优势

  • 解放运维人员:7X24小时监控,监控为例,监控帮你干活,你只需要处理问题就好。
  • 提升业务能力:业务初始化,自动备份,日志分析,你的工作脚本来做,效率更高。
  • 提升管理能力:从系统安装到业务部署,再到服务器管理维护,实现自动化运维,批量管理机器与业务。
  • 提升运维薪资:技术能力和工资成正比。

四、学了能干什么

重点:重复性的工作,全部通过脚本来完成。高效的同时还不出错。

  • 根据企业架构自定义监控系统,量身打造企业级监控系统
  • 业务初始化部署系统,业务初始化全部一键搞定,省去繁琐的安装与排错
  • 一键备份,分分钟搞定备份问题
  • 日志分析,繁琐又复杂的日志分析让机器取做吧。
  • 三方软件模块插件的编写:根据业务定制三方软件的功能,更贴合自己的业务。

五、学习什么内容

shell学习路线图.png

六、学习的技巧

好的编程是代码喂出来的。提升自己的代码量,把所有想到的事情都用代码实现出来

七、成长路径

shell编程掌握等级图.png

1.能看到代码实现的算法、原理
2、能根据自己的脚本应用要求修改脚本
3、能根据业务需求写脚本
4、能根据脚本执行问题优化脚本代码

八、学习环境

centos8:官网 centos.org

光盘镜像:http://mirrors.tuna.tsinghua.edu.cn/centos/8.2.2004/isos/x86_64/CentOS-8.2.2004-x86_64-dvd1.iso

编程语言与shell脚本

一、编程语言介绍

编程语言是指计算机能理解的语言,人类通过使用计算机语言可以给计算机批量下达任务,让其按照人类的思想去完成工作。最常见的语言有:汇编语言、C语言、java语言、php语言、Python语言、golang语言等等。

编程语言分类:

  • 编译型语言
    程序在执行之前需要一个专门的编译过程,把程序编译成为机器语言文件,运行时不需要重新翻译,直接使用编译的结果就行了。程序执行效率高,依赖编译器,跨平台性差些。如C、C++、java
  • 解释型语言
    程序不需要编译,程序在运行时由解释器翻译成机器语言,每执行一次都要翻译一次。因此效率比较低。比如Python/JavaScript/ Perl /ruby/Shell等都是解释型语言。

二、shell介绍

shell在计算机中起到什么作用呢?为什么要求shell呢,我们可以看看计算机操作系统的组成:

OS分层.png

看图之前问大家个问题,两个人在电话聊天:只会说法语的法国人,只会说汉语的你。如何沟通呢?

请个翻译在你两中间

同理,系统内核只知道二进制

如果你想给计算机内核下任务,让其驱动硬件干活,那么有两种选择

1、你学会二进制

2、找个翻译

1、shell介绍

shell就是我们找来的翻译

shell是一个程序,采用C语言编写,是用户和linux内核沟通的桥梁。它既是一种命令语言,又是一种解释性的编程语言。通过一个图表来查看一下shell的作用。

00_shell.png

2、bash shell基本特性

知己知彼方可百战百胜,如何应用Bash shell,我们先看看他的特性,有助于我们快速应用。

2.1、 命令和文件自动补全

Tab只能补全命令和文件 (RHEL6/Centos6)

2.2、 常见的快捷键—提升操作熟练度

^c    终止前台运行的程序
^z    将前台运行的程序挂起到后台
^d    退出 等价exit
^l    清屏 
^a |home   光标移到命令行的最前端
^e |end   光标移到命令行的后端
^u    删除光标前所有字符
^k    删除光标后所有字符
^r   搜索历史命令

3、shell脚本介绍

shell脚本是什么

简单来说就是将需要完成某个任务所执行的命令按照执行顺序保存到文本中,并给予执行权限。

 shell脚本精髓 学会60%

按照顺序执行。

它是解释型的,意味着不需要编译。

准确来说

若干命令 + 脚本的基本格式 + 脚本特定语法 + 思想= shell脚本

脚本命令演示
创建一个用户:harry     useradd harry
密码设置为:yunwei.98989 echo "yunwei.98989"|passwd --stdin harry
该用户创建文件夹/tmp/yebai   mkdir /tmp/yebai
该用户创建文件/tmp/yebai/README  touch /tmp/yebai/README
将“hello world“输入到/tmp/yebai/README  echo 'hello world' > /tmp/yebai/README

实现代码 01_task.sh
#!/bin/bash

#DESC: this is a test script 
#AUTHOR: Bai Shuming
#RELEASE: 1.0

#main 

#创建用户harry
useradd harry

#设置用户密码 yunwei.98989
echo "yunwei.98989"|passwd --stdin harry


#使用harry创建文件夹,文件,输入文件中内容
su - harry -c "mkdir /tmp/yebai"
su - harry -c "touch /tmp/yebai/README"
su - harry -c "echo 'hello world' > /tmp/yebai/README"

什么时候用到脚本?

重复化、复杂化的工作,通过把工作的命令写成脚本,以后仅仅需要执行脚本就能完成这些工作。

①自动化分析处理

②自动化备份

③自动化批量部署安装

④等等…

如何学习shell脚本?

尽可能记忆更多的命令

掌握脚本的标准的格式(指定魔法字节、使用标准的执行方式运行脚本)

必须熟悉掌握脚本的基本语法(重点)

学习脚本的秘诀:

多看(看懂)——>多模仿(多练)——>多思考

4、shell脚本语法

来吧,光说不练嘴把式,我们来看看如何书写一个脚本呢,写好一个脚本有哪些规范呢?

  • shell脚本组成

shell程序组成.png

  • 脚本命名
    nginx_install.sh 脚本名称 脚本扩展名 .sh
    名字不要太长 26个字节内
  • 代码规范:
1、#!/bin/bash
//脚本第一行, #!魔法字符,指定脚本代码执行的程序。即它告诉系统这个脚本需要什么解释器来执行,也就是使用
哪一种Shell

2、#代表注释,#!特例 

3、//以下内容是对脚本的基本信息的描述,大家可以根据实际情况尽可能的写详细一些,方便后续使用者
# Name: 脚本名字
# Desc:描述describe
# Path:存放路径
# Usage:用法
# Update:更新时间
# Author:作者
# Release: 分发版本

//下面就是脚本的具体内容
commands
...
  • 脚本执行方法:
    – 标准脚本执行方法(建议):
[root@yebai shell01]# cat 1.sh 
#!/bin/bash
#xxxx
#xxx
#xxx
hostname
date
[root@yebai shell01]# chmod +x 1.sh 
[root@yebai shell01]# ll
total 4
-rwxr-xr-x 1 root root 42 Jul 22 14:40 1.sh
[root@yebaishell01]# /shell/shell01/1.sh 
yebai
Sun Jul 22 14:41:00 CST 2018
[root@yebai shell01]# ./1.sh 
yebai
Sun Jul 22 14:41:30 CST 2018

– 非标准的执行方法(不建议):

[root@yebai shell01]# bash 1.sh 
yebai
Sun Jul 22 14:42:51 CST 2018
[root@yebai shell01]# sh 1.sh
yebai
Sun Jul 22 14:43:01 CST 2018
[root@yebai shell01]# 
[root@yebai shell01]# bash -x 1.sh
+ hostname
yebai
+ date
Sun Jul 22 14:43:20 CST 2018

-x:一般用于排错,查看脚本的执行过程
-n:用来查看脚本的语法是否有问题

注意:如果脚本没有加可执行权限,不能使用标准的执行方法执行,bash 1.sh

其他:
[root@yebaishell01]# source 2.sh
server
Thu Nov 22 15:45:50 CST 2018
[root@yebai shell01]# . 2.sh
server
Thu Nov 22 15:46:07 CST 2018

source 和 . 表示读取文件,执行文件里的命令

– 命令式脚本执行方法:

定义命令路径变量  PATH
PATH=$PATH:脚本路径

备注:脚本必须给执行权限

shell变量详解

一、变量介绍

在编程中,我们总有一些数据需要临时存放在内存,以待后续使用时快速读出。先了解一下计算机的存储单位吧。

计算机的单位:
1B=8bit

1KB=1024B
1MB=1024KB
1GB=1024MB
1TB=1024GB
1PB=1024TB
1EB=1024PB
1ZB=1024EB
...
好了,已经够大了!当然还有YB、BB更大的单位,同样进制也是1024.

1G=1024*1024*1024=1073741824B

假如你将一个1B的字符存入内存,如何读出呢?有没有一种大海捞针的感觉啊!我们讨论一下计算机是如何通过让我们人类快速将数据存在内存,如何从内存中读出数据的。我们研究过变量后就明白了。

变量:变量是编程中最常用的一种临时在内存中存取数据的一种方式。

变量存取原理

关于内存的说明
a、系统启动    内存被按照1B一个单位划分成N块     并且以十六进制为每一个空间编号

b、内存跟踪表记录  使用和未使用的内存的地址编号

c、内存申请    系统从未使用的内存中拿出一个或者一段连续空间  给你使用   同时在内存跟踪表中记录
该地址被占用不在分给别人,同时在系统中建立映射机制   
比如:变量名 STRING1=‘ABC’

name<==>0x5

d、释放内存
从内存跟踪表中将记录删除,下次存数据直接覆盖

变量存储.png

CHAR1(0x3)=A
从图片可以看出,当我们在脚本中定义变量存值的时候,可以从以下方面看到变化:
a、内存占用:如果存的是一个字符则占用1个字节,如果存的是字符串则是字符串的长度加1个字节长度(\0是一个
特殊字符,代表字符串结束)。

b、变量名与内存空间关系:计算机中会将对应的内存空间地址和变量名称绑定在一起,此时代表这段内存空间已经被
程序占用,其他程序不可复用;然后将变量名对应的值存在对应内存地址的空间里。

二、变量定义

2.1、什么时候需要定义变量?

如果某个内容需要多次使用,并且在代码中重复出现,那么可以用变量代表该内容。这样在修改内容的时候,仅仅需要修改变量的值。
在代码运作的过程中,可能会把某些命令的执行结果保存起来,后续代码需要使用这些结果,就可以直接使用这个变量。

2.2、定义一个变量

变量格式: 变量名=值

在shell编程中的变量名和等号之间不能有空格。

变量名命名规则:
    命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
    中间不能有空格,可以使用下划线(_)。
    不能使用标点符号。
    不能使用bash里的关键字(可用help命令查看保留关键字)。

定义变量举例:
VAR1=1
age=18 整形
name=‘baism’ 字符串
score=88.8 浮点

注意:字符串要用单引号或双引号引起来
建议变量名为大写,和命令区分
			_name

定义变量演示:

变量赋值,此种方法设置为本地变量
[root@yebai ~]# name="baism"
[root@yebai ~]# school='ayitula'
[root@yebai ~]# age=30
[root@yebai ~]# score=88.8

2.3、取消变量 unset

取消当前环境中的变量,如果是变量设置是保存在文件中,下次重启又会恢复
[root@yebai ~]# unset name
[root@yebai ~]# echo $name

2.4、 有类型变量 declare

-i 将变量看成整数
-r 使变量只读 readonly,该变量的值无法改变,并且不能为unset
-x 标记变量通过环境导出 export
-a 指定为索引数组(普通数组);查看普通数组
-A 指定为关联数组;查看关联数组

[root@yebai ~]# declare -i num='asa'
[root@yebai ~]# echo $num
0
[root@yebai ~]# num=100
[root@yebai ~]# echo $num
100
[root@yebai ~]# declare -r num
[root@yebai ~]# echo $num
100
[root@yebai~]# num=200
-bash: num: 只读变量

[root@yebai ~]# declare -x
declare -x HISTCONTROL="ignoredups"
declare -x HISTSIZE="1000"
declare -x HOME="/root"
declare -x HOSTNAME="Bai_Shuming"
declare -x LANG="zh_CN.UTF-8"
declare -x LESSOPEN="||/usr/bin/lesspipe.sh %s"

三、变量分类

系统中的变量根据作用域及生命周期可以分为四类:本地变量、环境变量、全局变量、内置变量

3.1、本地变量

用户自定义的变量,定义在脚本或者当前终端中,脚本执行完毕或终端结束变量失效。

3.2、环境变量

定义在用户家目录下的.bashrc或.bash_profile文件中,用户私有变量,只能本用户使用。

查看当前用户的环境变量 env

查询当前用户的所有变量(临时变量与环境变量) set

3.3、将当前变量变成环境变量 export

定义一个临时变量
1、
[root@yebai tmp]# export A=hello //临时将一个本地变量(临时变量)变成环境变量
[root@yebai tmp]# env|grep ^A
A=hello
2、
[root@yebai tmp]# A=HELLO
[root@yebai tmp]# export A

3、定义一个永久生效变量:
vim .bash_profile 或者 ~/.bashrc
A=hello


关于export说明
用户登录时:
1) 用户登录到Linux系统后,系统将启动一个用户shell。在这个shell中,可以使用shell命令或声明变量,也可以
创建并运行 shell脚本程序。

运行脚本时:
2) 运行shell脚本程序时,系统将创建一个子shell。此时,系统中将有两个shell,一个是登录时系统启动的shell,
另一个是系统为运行脚本程序创建的shell。当一个脚本程序运行完毕,它的脚本shell将终止,可以返回到执行该脚本
之前的shell。

从这种意义上来说,用户可以有许多 shell,每个shell都是由某个shell(称为父shell)派生的。
在子shell中定义的变量只在该子shell内有效。如果在一个shell脚本程序中定义了一个变量,当该脚本程序运行时,
这个定义的变量只是该脚本程序内的一个局部变量,其他的shell不能引用它,要使某个变量的值可以在其他shell中
被改变,可以使用export命令对已定义的变量进行输出。 

export命令将使系统在创建每一个新的shell时定义这个变量的一个拷贝。这个过程称之为变量输出。

父shell与子shell

shell父子关系.png

3.4、全局变量

使用export命令将本地变量输出为当前shell中的环境变量
所有用户及shell都可以使用,可以在/etc/profile /etc/bashrc下永久定义

打印全局变量 printenv

定义格式
export SCHOOL='yebai'


测试方法:
通过不同用户登录测试是否能读取变量

3.5、内置变量

系统变量(内置bash中变量) : shell本身已经固定好了它的名字和作用.

$?:上一条命令执行后返回的状态,当返回状态值为0时表示执行正常,非0值表示执行异常或出错
 若退出状态值为0,表示命令运行成功
 若退出状态值为127,表示command not found
 若退出状态值为126,表示找到了该命令但无法执行(权限不够)
 若退出状态值为1&2,表示没有那个文件或目录
 
$$:当前所在进程的进程号     echo $$   eg:kill -9 `echo $$`  = exit   退出当前会话

$!:后台运行的最后一个进程号  (当前终端)  # gedit &
!$ 调用最后一条命令历史中的参数
!! 调用最后一条命令历史


$#:脚本后面接的参数的个数
$*:脚本后面所有参数,参数当成一个整体输出,每一个变量参数之间以空格隔开
$@: 脚本后面所有参数,参数是独立的,也是全部输出

$0:当前执行的进程/程序名  echo $0     
$1~$9 位置参数变量
${10}~${n} 扩展位置参数变量  第10个位置变量必须用{}大括号括起来
./1.sh a b c

[root@yebai shell01]# cat 2.sh 
#!/bin/bash
#xxxx
echo "\$0 = $0"
echo "\$# = $#"
echo "\$* = $*"
echo "\$@ = $@"
echo "\$1 = $1" 
echo "\$2 = $2" 
echo "\$3 = $3" 
echo "\$11 = ${11}" 
echo "\$12 = ${12}" 

了解$*和$@的区别:
$* :表示将变量看成一个整体
$@ :表示变量是独立的

#!/bin/bash
for i in "$@"
do
echo $i
done

echo "======我是分割线======="

for i in "$*"
do
echo $i
done

[root@yebai shell01]# bash 3.sh a b c
a
b
c
======我是分割线=======
a b c

变量总结说明:

本地变量:当前用户自定义的变量。当前进程中有效,其他进程及当前进程的子进程无效。

环境变量:当前进程有效,并且能够被子进程调用。

全局变量:全局所有的用户和程序都能调用,且继承,新建的用户也默认能调用.

内置变量:shell本身已经固定好了它的名字和作用.

变量类型作用域生命周期
本地变量当前shell环境(子shell不能用)脚本结束或终端结束
环境变量当前shell或者子shell当前进程结束
全局变量所有用户及shell环境关机
内置变量所有用户及shell环境关机

四、变量取值

读取变量内容符: 读取方法:变量名

变量内容读出
[root@yebai ~]# echo $name
baism
[root@yebai ~]# echo $school
ayitula
[root@yebai ~]# echo $age
30
[root@yebai ~]# echo $score
88.8

注意

变量读取过程中,默认单引号是不解释变量的.比如
[root@yebai ~]# echo '$name'
$name

如果必须使用单引号还要读取变量的值可以使用eval命令[重新运算求出参数的内容] 
[root@yebai ~]# eval  echo '$name'
baism

五、其他变量(扩展)

1)取出一个目录下的目录和文件:dirname和 basename 
2)变量"内容"的删除和替换
一个“%”代表从右往左去掉一个/key/
两个“%%”代表从右往左最大去掉/key/
一个“#”代表从左往右去掉一个/key/
两个“##”代表从左往右最大去掉/key/

# A=/root/Desktop/shell/mem.txt 
# echo $A
/root/Desktop/shell/mem.txt
# dirname $A   取出目录
/root/Desktop/shell
# basename $A  取出文件
mem.txt

# url=www.taobao.com
# echo ${#url}      获取变量的长度
# echo ${url#*.}       以分隔符.界限  *匹配所有
# echo ${url##*.}
# echo ${url%.*}
# echo ${url%%.*}

shell脚本实战案例-数据磁盘初始化

一、案例应用场景

生产环境中的服务器一般会分为系统盘和数据盘两种磁盘,以dell R730举例,该服务器是一个2U的机架式服务器,满载可以挂载14块磁盘[2块在机箱内做系统盘,12块在面板做数据盘],我们一般的策略是系统盘做raid1,保障系统稳定性12块数据磁盘我们做raid10 或者 raid50,保障数据盘容错的同时还能做到优化IO的效果。

raid磁盘的容量是一定的,线上的数据又是不断增长的,也就是说总有一天会把你的数据磁盘填满,那怎么办?为了解决这个问题,人们想到了LVM[逻辑卷管理系统],当前数据盘容量不够用的时候,我们可以通过san存储获得网络磁盘,然后将该网络存储动态加入LVM中的卷组后就可以扩大LV了。整个过程采用在线扩容的方式,不会影响线上业务正是基于这个原因,我们又在系统中把raid数据盘在存数据之前做成了LVM磁盘,方便后续的扩容。

注意:有数据的磁盘不能再做LVM,因为需要格式化,数据会全部丢失。必须提前布局,否则就得提前准备跑路资金了。

二、案例需求

给虚拟机添加一块磁盘(以sdb为例),要求使用脚本对该磁盘分三个区:

 1)主分区 /dev/sdb3 543M 文件系统 ext4 要求开机自动挂载到/data/data1目录

 2) 逻辑分区 /dev/sdb5 2G

 3) 逻辑分区 /dev/sdb6 3G

使用/dev/sdb5 /dev/sdb6 新建卷组vg100,并创建一个PE为16M,容量为2.5G的逻辑卷lv100,
格式化为xfs,默认开机自动挂载到/data/data2目录

三、案例算法

算法:完成一个任务的代码思路。

脚本思路---算法
1、分区
2、创建逻辑卷
    2.1  创建物理卷
    2.2  创建卷组
    2.3  创建逻辑卷
3、格式化 /dev/sdb3   /dev/vg100/lv100
4、修改/etc/fstab文件
5、挂载分区
6、验证并输出挂载结果

四、代码实现

代码实现的要点:要清楚每一步的步骤,不同的系统可能有细微的差别,一味的复制可不行的,需要提前手动做一下,把步骤捋清楚。

实验代码    01_disk_partition.sh
#!/bin/bash
# 
#Author: Bai Shuming
#Created Time: 2019/11/1 21:05
#Release: 
#Description:
#
#给虚拟机添加一块磁盘(以sdb为例),要求使用脚本对该磁盘分三个区:
#  1)主分区 /dev/sdb3   543M   文件系统 ext4  要求开机自动挂载到/data/data1目录
#  2)   逻辑分区  /dev/sdb5   2G
#  3)   逻辑分区  /dev/sdb6   3G
#使用/dev/sdb5   /dev/sdb6   新建卷组vg100,并创建一个PE为16M,容量为2.5G的逻辑卷lv100,
#格式化为xfs,默认开机自动挂载到/data/data2目录

#1、分区
fdisk /dev/sdb <<EOF
n
p
3

+543M
n
e
4


n

+2G
n

+3G
w
EOF

#2、创建逻辑卷
   #2.1 创建物理卷
    pvcreate /dev/sdb5 /dev/sdb6
   #2.2 创建卷组
    vgcreate -s 16M vg100 /dev/sdb{5..6}
   #2.3 创建逻辑卷
    lvcreate -L 2.5G -n lv100 vg100
#3、格式化
mkfs.ext4 /dev/sdb3
mkfs.xfs /dev/vg100/lv100

#4、修改/etc/fstab,实现自动挂载
echo  "/dev/sdb3   /data/data1 ext4  defaults   0 0" >> /etc/fstab
echo "/dev/vg100/lv100 /data/data2  xfs   defaults 0 0" >> /etc/fstab

#5、挂载分区
mkdir -p /data/data{1..2}
mount -a

#6、验证并输出挂载结果
mount |grep "/dev/sdb3"
test $? -eq 0&&echo "/dev/sdb3 挂载成功" || echo "/dev/sdb3挂载失败"

##注意检索的时候,mount输出中LV的表示方式,或者直接检索挂载点/data/data2也可以。
mount |grep "vg100-lv100"
test $? -eq 0&&echo "/dev/vg100/lv100 挂载成功" || echo "/dev/vg100/lv100挂载失败"

五、实现验证

使用如下命令查看是否挂载成功
[root@yebai ~]# df -Th

shell脚本格式化输出

计算机程序其实就是三步:输入、运算、输出,这个理论也适应于shell编程。

那么计算机是如何将信息按照比较舒服的格式输出到屏幕或者KFC的打印纸上的呢!如果让计算机能够输出一种格式,让人看起来很舒服,那么我们就要学习一下计算机的格式化输出,让计算机程序将信息输出的时候美美哒!让人一目了然看到需要的信息。

一、shell格式化输出

一个赏心悦目的界面是一个程序给用户的第一个映像,好的界面可以让用户更加容易上手使用。windows之所以能被个人用户喜欢就是因为它的界面更加容易和用户交互,只要用户能识别文字,懂得点击鼠标就能操作电脑;而linux之所以无法被广大个人用户使用的瓶颈就是图形界面无法完成所有工作,需要命令配合才可以,这就把非专业用户拒之门外了,想用就必须去学习命令。
我们在使用shell写一个程序的时候,如果想让广大的用户都能使用,都能快速上手,那么好的交互界面就太重要了。我们可以使用多种方法开发好的、易交互的界面,常用的工具有:dialog、echo、printf等命令。
本节课主要给大家介绍一个最简单易用的命令:echo

1、echo命令

功能:将内容输出到默认显示设备

应用场景:需要计算机程序输出的地方

echo命令的功能是在显示器上显示一段文字,一般起到一个提示的作用。 功能说明:显示文字。

语法:echo [-ne][字符串]

补充说明:
1、echo会将输入的字符串送往标准输出。
2、输出的字符串间以空白字符隔开,并在最后加上换行号。

OPTIONS:
-n	不要在最后自动换行
-e	若字符串中出现以下字符,则特别加以处理,而不会将它当成一般文字输出:

转义字符
\a	发出警告声;
\b	删除前一个字符;
\t	插入tab;
\n	换行且光标移至行首;

\c	最后不加上换行符号;
\f	换行但光标仍旧停留在原来的位置;
\r	光标移至行首,但不换行;
\v	与\f相同;
\		插入\字符;
\0nnn	打印nnn(八进制)所代表的ASCII字符;  备注:数字0  不要理解成字母o
\xNN  打印NN(十六进制)所代表的ASCII字符;

-–help	显示帮助
-–version显示版本信息


你的进制转换过关吗?
[root@yebai ~]# echo -e "\0123"   #ot(123) = 83  对应ascii表的S
S
[root@yebai ~]# echo -e "\x61"   #ox(61) = 97  对应ascii表的a
a
2、输出颜色字体

脚本中echo显示内容带颜色显示,echo显示带颜色,需要使用参数-e

格式如下:

echo -e "\033[字背景颜色;文字颜色m字符串\033[0m"

例如: echo -e “\033[41;36m something here \033[0m”

其中41的位置代表底色, 36m的位置是代表字的颜色

1、字背景颜色和文字颜色之间是英文的

2、文字颜色后面有个m

3、字符串前后可以没有空格,如果有的话,输出也是同样有空格

下面是相应的字和背景颜色,可以自己来尝试找出不同颜色搭配

  例
  echo -e “\033[31m 红色字 \033[0m”
  echo -e “\033[34m 黄色字 \033[0m”
  echo -e “\033[41;33m 红底黄字 \033[0m”
  echo -e “\033[41;37m 红底白字 \033[0m”
  
字颜色:30—–37
  echo -e “\033[30m 黑色字 \033[0m”
  echo -e “\033[31m 红色字 \033[0m”
  echo -e “\033[32m 绿色字 \033[0m”
  echo -e “\033[33m 黄色字 \033[0m”
  echo -e “\033[34m 蓝色字 \033[0m”
  echo -e “\033[35m 紫色字 \033[0m”
  echo -e “\033[36m 天蓝字 \033[0m”
  echo -e “\033[37m 白色字 \033[0m”

  
字背景颜色范围:40—–47
  echo -e “\033[40;37m 黑底白字 \033[0m”
  echo -e “\033[41;37m 红底白字 \033[0m”
  echo -e “\033[42;37m 绿底白字 \033[0m”
  echo -e “\033[43;37m 黄底白字 \033[0m”
  echo -e “\033[44;37m 蓝底白字 \033[0m”
  echo -e “\033[45;37m 紫底白字 \033[0m”
  echo -e “\033[46;37m 天蓝底白字 \033[0m”
  echo -e “\033[47;30m 白底黑字 \033[0m”
  
最后面控制选项说明
  \033[0m 关闭所有属性
  \033[1m 设置高亮度
  \033[4m 下划线
  \033[5m 闪烁
  \033[7m 反显
  \033[8m 消隐

  \033[30m — \33[37m 

设置前景色
  \033[40m — \33[47m 设置背景色
  
  
  \033[nA 光标上移n行
  \033[nB 光标下移n行
  \033[nC 光标右移n行
  \033[nD 光标左移n行
  \033[y;xH设置光标位置
  \033[2J 清屏
  \033[K 清除从光标到行尾的内容
  \33[s 保存光标位置
  \033[u 恢复光标位置
  \033[?25l 隐藏光标
  \033[?25h 显示光标
  
用法例子  光标下移三行  
[root@yebai ~]# echo -e "\033[0m today is fine \033[3B"
 today is fine 
3、jobs

需求:输出一个水果购物界面 fruits_shop.sh

image20190612094713385.png

案例要点:

  • echo输出缩进问题
  • 字体颜色输出

代码实现:

job代码    01_fruits_shop.sh
#!/bin/bash
# 
#Author: www.yebai.com
#Release: 
#Description:打印水果超市列表

echo -e "\t\t    \033[32m Fruits List \033[0m      \n"
echo -e "\t   \033[31mFruit\033[0m   \t\t \033[31mPrice\033[0m \t\t\033[31mWeight\033[0m"
echo -e "\t\033[34m1)Apple\t\t¥10.00\t\t1KG\033[0m"
echo -e "\t\033[34m2)Banana\t¥9.00\t\t1KG\033[0m"
echo -e "\t\033[34m3)Orange\t¥15.20\t\t1KG\033[0m"

shell脚本用户交互

阅读 (4534)

分享

学会了输出,那么输出什么呢?当然是人类让计算机运算的数据,那么运算的数据来自哪里?

可以肯定是你或其他人给的,那如何给程序数据呢?

那么我们就得看看如何实现人机交互了。

  • 比如计算机程序
  • 比如信息录入系统

一、read命令

功能:默认接受键盘的输入,回车符代表输入结束
应用场景:人机交互
命令选项

-p打印信息
-t限定时间
-s不回显
-n输入字符个数

二、交互输入案例

案例需求:
写一个系统用户交互登录界面脚本,仿linux文本界面登录
案例要点:
了解linux文本界面登陆所需要的输出信息及界面布局

login.gif

job实现步骤:
1、根据linux文本界面登陆窗口输出信息,打印登陆提示信息
2、交互输入登陆账号
3、交互输入登陆密码

代码实现:

#job实现代码   02_login.sh
#!/bin/bash
# 
#Author: www.yebai.com
#Release: 
#Description: 仿真登陆

IP=`ifconfig ens33|egrep -w "inet"|awk '{print $2}'`

#1、清屏
clear
#2、输出提示信息
echo "CentOS Linux 8 (Core)"
echo -e "Kernel `uname -r` on an `uname -m`\n"

echo -e "Web console: https://localhost:9090/ or https://$IP:9090/ \n"

#3、交互输入登陆名
echo -n "$HOSTNAME login: "
read account

#4、交互输入密码
read -s -t30 -p "Password: " pw
echo

shell运算详解

计算机编程就是三大步:输入、运算、输出

那么计算机运算有哪些呢,计算机能做哪些运算呢?

我们来看看常见的计算机运算

一、赋值运算

赋值运算符 =

 	a=10   
 	name='baism'
 
 重点:字符串必须用引号引起来

二、算术运算[四则运算]

2.1 运算符与命令

四则运算符: + - * \ 【加减乘除】
扩展: % ** 【取余 开方】

运算命令:

  • 整形运算
    – expr
    – let
    – $(())
    – bc
  • 浮点运算
    – bc

2.2 整形运算

expr 命令:只能做整数运算,格式比较古板,注意空格

[root@yebai ~]# expr 1 + 1
2
[root@yebai ~]# expr 5 - 2
3
[root@yebai ~]# expr 5 \* 2  #注意*出现应该转义,否则认为是通配符
10
[root@yebai ~]# expr 5 / 2
2
[root@yebai ~]# expr 5 % 2
1

let命令:只能做整数运算,且运算元素必须是变量,无法直接对整数做运算

[root@yebai ~]# let a=100+3;echo $a
103
root@yebai ~]# let a=100-3;echo $a
97
[root@yebai ~]# let a=100/3;echo $a
33
[root@yebai ~]# let a=100*3;echo $a
300
[root@yebai ~]# let a=100%3;echo $a
1
[root@yebai ~]# let a=100**3;echo $a
1000000
[root@yebai ~]# a=100
[root@yebai ~]# let a++;echo $a
101
[root@yebai ~]# let a--;echo $a
100
[root@yebai ~]# let a-=3;echo $a
97
[root@yebai ~]# let a+=5;echo $a
102

双小圆括号运算,在shell中(( ))也可以用来做数学运算

[root@yebai ~]# echo $(( 100+3))
103
[root@yebai ~]# echo $(( 100-3)) 
97
[root@yebai ~]# echo $(( 100%3))
1
[root@yebai ~]# echo $(( 100*3))
300
[root@yebai ~]# echo $(( 100/3))
33
[root@yebai ~]# echo $(( 100**3))     #开方运算
1000000

2.3 浮点运算

浮点运算是采用的命令组合的方式来实现的 echo “scale=N;表达式”|bc

[root@yebai ~]# echo "scale=2;3+100"|bc
103
[root@yebai ~]# echo "scale=2;100-3"|bc
97
[root@yebai ~]# echo "scale=2;100/3"|bc
33.33
[root@yebai ~]# echo "scale=2;100*3"|bc
300

2.4、练习案例

2.4.1 实现一个四则运算计算器

案例思考: 计算器的功能: + - * \

实现步骤:
1、要求用户传输三个参数,num1 算术运算符 num2
2、运算输出结果

实现代码

##03_calculator.sh
#!/bin/bash
# 
#Author: www.yebai.com
#Release: 
#Description: 简单计算器

echo "$1 $2 $3"|bc
2.4.2 内存使用率统计,要求打印内存使用率

案例思考:

  • 物料1、内存总量 获得方式是什么 free top /proc/meminfo
  • 物料2、内存使用量
  • 物料3、内存使用率公式 使用量/总量*100%

实现步骤:

  • 1、获取内存总量
  • 2、获取内存使用量
  • 3、运算输出结果

实现代码

#job实现代码  04_memory_use.sh
#!/bin/bash
# 
#Author: www.yebai.com
#Release: 
#Description:内存使用率计算脚本

#free
#1、获得内存总量
memory_total=`free -m|grep -i "mem"|tr -s " "|cut -d " " -f2`

#2、获得内存使用的量
memory_use=`free -m|grep -i "mem"|tr -s " "|cut -d " " -f3`

#3、计算输出
#运算的时候是否需要小数点 浮点运算,要考虑使用的命令 (难点 重点)
#echo "内存使用率: $((memory_use*100/memory_total))%"
#难点:浮点运算中,同优先级的情况下,大数除以小数 尽可能保证精确
echo "内存使用率: `echo "scale=2;$memory_use*100/$memory_total"|bc`%"

实现效果

#运算结果
[root@yebai day2]# sh memory_use.sh 
Memory使用率: 2.61%

三、比较运算

计算机除了算术和赋值运算外,还有比较运算,比如说比较两个数的关系,比较两个字符串的关系【用户登录系统】等。接下来我们学习如何在shell中进行比较运算

3.1、整形比较运算

					运算符解释:

 精确比较
        -eq         等于 equal

        -gt         大于

        -lt         小于

 模糊比较
        -ge         大于或等于

        -le         小于或等于

        -ne         不等于

通过test命令比较两个整数关系

[root@yebai ~]# test 100 -gt 300;echo $?
1
[root@yebai ~]# test 100 -ge 300;echo $?
1
[root@yebai ~]# test 100 -eq 300;echo $?
1
[root@yebai ~]# test 100 -le 300;echo $?
0
[root@yebai ~]# test 100 -lt 300;echo $?
0
[root@yebai ~]# test 100 -ne 300;echo $?
0

备注:linux命令test只能比较两个整数的关系,不会返回结果,需要通过$?才能看到结果

3.2 练习案例

3.2.1 写一个脚本实现对两个证书关系的判断

案例思考:
两个数有几种关系?

  • 1、大于
  • 2、小于
  • 3、等于

实现步骤

  • 1、交互或者外传参的方式获得两个整数
  • 2、判断关系
  • 3、输出结果

实现代码

#!/bin/bash
# 
#Author: www.yebai.com
#
#Release: 
#Description:判断两个数的关系

#1、输入两个数,$1 $2

#2、判断两个数关系
if [ $1 -gt $2 ];then
  #3、输出结果
  echo "$1 > $2 "
elif [ $1 -eq $2 ];then
  echo "$1 = $2"
else
  echo "$1 < $2"
fi

实现结果:

比较两个数关系.gif

3.2.2 判断两个浮点数的关系

案例思考
shell中的浮点类型如何做比较运算?

默认情况下shell是不能判断浮点的,那么在linux中又避免不了需要进行浮点运算,那怎么解决

解决思路如下:
1)两个数据同时放大到整数倍
2)处理掉小数点位,保留整数位
3)进行整形判断

实现代码

#!/bin/bash
# 
#Author: www.yebai.com
#
#Release: 
#Description:判断两位小数点的关系

#1、交互或者外传参的方式获得两个整数
#$1 $2
[ $# -lt 2 ]&&echo "need two args"&&exit 1

#采用外传参的方式接收数据并放大100倍,并处理为整数
num1=`echo "scale=2;$1*100"|bc|cut -d "." -f1`
num2=`echo "scale=2;$2*100"|bc|cut -d "." -f1`

#2、比较运算
if [ $num1 -gt $num2 ];then
   #3、输出结果
   echo "$1 > $2"
elif [ $num1 -lt $num2 ];then
   echo "$1 < $2"
else
   echo "$1 = $2"
fi

实现结果

比较两个浮点数关系.gif

3.3、字符串比较运算

3.3.1 字符串比较运算符
运算符解释,注意字符串一定别忘了使用引号引起来
  ==          等于   
  !=          不等于
  -n          检查字符串的长度是否大于0  
  -z          检查字符串的长度是否为0
3.3.2 比较两个字符串关系
[root@yebai ~]# test 'root' == 'root';echo $?
0
[root@yebai ~]# test 'root' != 'root1';echo $?
0
[root@yebai ~]# name=
[root@yebai ~]# test -n "$name";echo $?
1
[root@yebai ~]# test -z "$name";echo $?
0
3.3.3 练习案例

案例需求:
模拟一个linux文本界面登陆程序,要求账号密码验证成功进入系统,账号密码验证失败退回登陆界面

案例思考:

  • 1、熟悉linux文本界面登陆步骤
  • 2、熟悉字符串比较运算

案例步骤:

  • 1、预设正确账号、密码
  • 2、输出提示登录信息并实现交互登录
  • 3、输出密码输入信息并实现交互
  • 4、判断输入是否正确
    – 4.1)正确,进入系统
    – 4.2)不正确 继续运行该脚本

实现代码

#!/bin/bash
# 
#Author: www.yebai.com
#Created Time: 
#Release: 
#Description: 仿真登陆
####
default_account='root'
default_pw='123456'


######main
#1、清屏
clear
#2、输出提示信息
echo "CentOS Linux 7 (Core)"
echo -e "Kernel `uname -r` on an `uname -m`\n"

#3、交互输入登陆名
echo -n "$HOSTNAME login: "
read account

#4、交互输入密码
read -s -t30 -p "Password: " pw

#5、判断用户输入是否正确
if [ "$default_account" == "$account" ] && [ "$default_pw" == "$pw" ];then
   clear
   echo -e "\nwelcome to root"
else
   echo  "用户名或密码错误..."
   #输入错误,再次调用本脚本
   sh $0
fi

实现效果
账号:root 密码:123456

仿真登陆01.gif

四、逻辑运算

完成一个任务中需要多个条件都满足或者多个条件中只要满足一个即可,那么这就是我们的逻辑运算。
通过多个条件判断结果,才能得出结论

4.1、逻辑运算应用场景
多条件同时判断
4.2、逻辑运算符
  • 逻辑与运算 &&
  • 逻辑或运算 ||
  • 逻辑非运算 !

逻辑运算秘籍

逻辑运算注意事项:
    逻辑与 或 运算都需要两个或以上条件
    逻辑非运算只能一个条件。
    口诀:     逻辑与运算               真真为真 真假为假   假假为假
             逻辑或运算               真真为真 真假为真   假假为假
             逻辑非运算               非假为真   非真为假
             
             
逻辑与或的短路运算
逻辑与中靠前的条件中出现了假,后面的就不在判断了,因为已经是假的了
逻辑或中靠前的条件中出现了真,后不在往后判断了,结果已经为真了

4.3、练习案例

明白了逻辑运算符和逻辑运算的口诀和短路运算后,我们来通过练习加深理解,接下来我们来看一个案例。
上一个字符串运算练习案例(3.3.3)中我们练习的是仿真用户登录,判断登陆的方式是分步判断的,既先判断用户名,不管是否正确都会继续判断密码的正确性,这样是两步判断,既然已知用户名是错误的啦,完全没必要在判断密码的正确性了,因为结果都一样,你不能进入系统。既然判断一个用户输入的用户名和密码是否正确,且一个不正确就不能进入系统,那么我们可以这么去思考一下:两个条件全为真则进入系统,两个条件一个为假则重新登陆。这样是不是就满足了逻辑与运算了,同时思考逻辑与运算的短路运算,逻辑与条件中的判断顺序是从前往后,前边一个条件为假的时候,后边的条件就不用判断了,那么就减少了判断的次数,加快了运算速度。你品!你细品!!是不是这个道理。

4.3.1、就按照刚才的思路再去写一个升级版的仿真用户登录系统。

案例需求
使用逻辑运算写一个仿真用户登录验证程序

案例思路

  • 1、输入用户名
  • 2、输入密码
  • 3、与运算返回结果

案例代码

#!/bin/bash
echo "CentOS linux 8 (Core)"
echo -e "Kernel `uname -r` on an `uname -m` \n"

#1、输入用户名
echo -n "$HOSTNAME login: "
read myuser

#echo -n "password: "
#read -s -t 5 -n 2 pw

#2、输入密码
read -p "password: " -s -t 5 -n 6 pw

#3、与运算返回结果
[ $myuser == 'root' ] && [ $pw == '123456' ] && echo yes || echo no
4.3.2 丈母娘择婿

案例需求
伟大、慈祥的丈母娘有女儿,她想给自己的女儿选一个女婿,所以就想通过网上招婿的方式去处理,为了节约成本,让你帮忙开发一个小程序来自动过滤一下不满足条件的男士。
改程序为了能够满足大量丈母娘的需求,所以可以根据女儿的年龄做出不同的判断

  • 姑娘20岁 应征男士条件:房子需要两套及以上、存款100W及以上、车子1辆以上,条件必须全部满足
  • 姑娘30岁 应征男士条件:房子需要两套及以上、存款100W及以上、车子1辆以上,条件满足其中一个即可
  • 姑娘40岁 应征男士条件:是男的都可以报名
    注意:应征者必须全是男性

案例思考
因为是多条件判断,复合逻辑运算的条件,重点在不同年龄段的逻辑判断方式!

案例步骤

  • 1、要求传入两个参数:姑娘年龄、应征者行吧
  • 2、交互输入用户条件
  • 3、判断用户条件并输出结果

案例代码

#!/bin/bash
# 
#Author: www.yebai.com
#
#Release: 
#Description: 丈母娘选女婿  练习逻辑运算

cat <<EOF
游戏规则:
    1)根据交互输入信息,让脚本去判断是否满足条件。
    2)判断条件如下:
        第一次 姑娘20岁    要求应征男子报名条件 房子需要两套及以上、存款100W及以上、车子1辆以上
	第二次 姑娘30岁               			以上条件满足一个即可
	第三次 姑娘40岁					是男的都可以报名
    3) 脚本执行方法  $0 姑娘年龄[20|30|40] 应征者性别[男|女]
EOF


#1、判断传递参数数量,要求两个
if [ $# -lt 2 ];then
   echo 'need two args $1 $2'
   exit 1
fi

#2、交互输入
read -p "请输入你的存款: " money
read -p "请输入你的房子数量: " zhangse
read -p "请输入你车子的数量: " car

#3、判断应征条件,并给出结果
#姑娘20岁代码
if [ $1 -eq 20 ] && [ $money -gt 1000000 ] && [ $zhangse -ge 2 ] && [ $car -ge 1 ] && [ "$2" == "男" ];then
    echo "初始通过,等待姑娘复试吧"
#姑娘30岁代码
elif [ $1 -eq 30 ] && [ "$2" == "男" ] && ( [ $money -gt 1000000 ] || [ $zhangse -ge 2 ] || [ $car -ge 1 ] );then
    echo "初始通过,等待姑娘复试吧"
#姑娘40岁代码
elif [ $1 -eq 40 ] && [ ! $2 == "女" ];then
    echo "初始通过,等待姑娘复试吧"
else
   echo "你不满足条件,byebye"
fi

五、文件判断[文件类型、权限、新旧判断]

linux的设计思路:一切皆文件,对文件系统的操作其实可以狭隘的理解为对文件的操作。如果希望对文件类型和权限或者两个文件做新旧或者是否同一个文件进行判断。

5.1、test判断命令

命令功能: 检测文件类型和比较运算

命令用法

			test [命令选项] 表达式

命令选项

-d  检查文件是否存在且为目录
-e  检查文件是否存在
-f  检查文件是否存在且为文件
-r  检查文件是否存在且可读
-s  检查文件是否存在且不为空
-w  检查文件是否存在且可写
-x  检查文件是否存在且可执行
-O  检查文件是否存在并且被当前用户拥有
-G  检查文件是否存在并且默认组为当前用户组
-nt file1 -nt file2  检查file1是否比file2新
-ot file1 -ot file2  检查file1是否比file2旧     
-ef file1 -ef file2  检查file1是否与file2是同一个文件,判定依据的是i节点

以上只列出部分命令选项,详细的可以通过:man test获得。

命令用法练习

文件类型
[root@yebai ~]# test -f /etc/passwd;echo $?
0
[root@yebai ~]# test -f /etc;echo $?
1
[root@yebai ~]# test -d /etc;echo $?
0

权限判断
[root@yebai ~]# test -x /root/anaconda-ks.cfg ;echo $?
1
[root@yebai ~]# ll /root/anaconda-ks.cfg 
-rw-------. 1 root root 1216 6月  26 09:06 /root/anaconda-ks.cfg
[root@yebai ~]# test -r /root/anaconda-ks.cfg ;echo $?
0

[root@yebai ~]# test -w /root/anaconda-ks.cfg ;echo $?
0

5.2、练习案例

案例需求
写一个平滑关闭服务脚本。

案例思路

  • 判断服务进程文件是否存在,存在读取PID并判断是否存在进程
  • 进程存在就使用Kill命令结束服务
  • 不存在就报“服务已经结束“

案例步骤
1、检查服务PID文件
2、检查进程是否存在
3、杀死进程

案例代码

#!/bin/bash
# 
#Author: www.yebai.com
#
#Release: 
#Description:找到服务的PID号,如果服务开启则杀死,否则提示服务已经关闭或不存在

#1、判断PID
#注意PID的路径,如果服务的PID不在这里可以做个软连接
if [ -f /var/run/$1.pid ];then
   #2、如果存在
   PID=`cat /var/run/$1.pid`
   #3、统计进程数
   process_num=`ps aux|grep $PID|wc -l`
   #5、判断进程数大于2则杀死
   if [ $process_num -ge 2 ];then
       kill -s QUIT $PID 
   else
   #5、判断小于2则提示进程不存在,同时删除服务PID文件
   	echo "service $1 is close"
        rm -f /var/run/$1.pid
   fi
else
   #2、不存在
   echo "service $1 is close"
fi
个文件进行判断。

## 5.1、test判断命令

**命令功能:** 检测文件类型和比较运算

**命令用法**

		test [命令选项] 表达式

**命令选项**

-d 检查文件是否存在且为目录
-e 检查文件是否存在
-f 检查文件是否存在且为文件
-r 检查文件是否存在且可读
-s 检查文件是否存在且不为空
-w 检查文件是否存在且可写
-x 检查文件是否存在且可执行
-O 检查文件是否存在并且被当前用户拥有
-G 检查文件是否存在并且默认组为当前用户组
-nt file1 -nt file2 检查file1是否比file2新
-ot file1 -ot file2 检查file1是否比file2旧
-ef file1 -ef file2 检查file1是否与file2是同一个文件,判定依据的是i节点

以上只列出部分命令选项,详细的可以通过:man test获得。


**命令用法练习**

文件类型
[root@yebai ~]# test -f /etc/passwd;echo $?
0
[root@yebai ~]# test -f /etc;echo $?
1
[root@yebai ~]# test -d /etc;echo $?
0

权限判断
[root@yebai ~]# test -x /root/anaconda-ks.cfg ;echo $?
1
[root@yebai ~]# ll /root/anaconda-ks.cfg
-rw-------. 1 root root 1216 6月 26 09:06 /root/anaconda-ks.cfg
[root@yebai ~]# test -r /root/anaconda-ks.cfg ;echo $?
0

[root@yebai ~]# test -w /root/anaconda-ks.cfg ;echo $?
0


## 5.2、练习案例

**案例需求**
写一个平滑关闭服务脚本。

**案例思路**

- 判断服务进程文件是否存在,存在读取PID并判断是否存在进程
- 进程存在就使用Kill命令结束服务
- 不存在就报“服务已经结束“

**案例步骤**
1、检查服务PID文件
2、检查进程是否存在
3、杀死进程

**案例代码**

#!/bin/bash

#Author: www.yebai.com

#Release:
#Description:找到服务的PID号,如果服务开启则杀死,否则提示服务已经关闭或不存在

#1、判断PID
#注意PID的路径,如果服务的PID不在这里可以做个软连接
if [ -f /var/run/$1.pid ];then
#2、如果存在
PID=cat /var/run/$1.pid
#3、统计进程数
process_num=ps aux|grep $PID|wc -l
#5、判断进程数大于2则杀死
if [ $process_num -ge 2 ];then
kill -s QUIT $PID
else
#5、判断小于2则提示进程不存在,同时删除服务PID文件
echo “service $1 is close”
rm -f /var/run/$1.pid
fi
else
#2、不存在
echo “service $1 is close”
fi

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MagnumOvO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值