shell—初识shell
本文最后更新于 208 天前,如有失效请评论区留言。

Auther | CuckooYang

初识shell

程序 语言 编程
----------------------------------
语言
自然语言:汉语、英语 
计算机语言:c语言、c++、(java php python go shell) 
编译型语言 c c++ java 
解释型语言  php python  bash
  • 编译型语言:

    编译型语言的首先将源代码编译生成机器语言,再由机器运行机器码(二进制)。像C/C++等都是编译型语言。

  • 解释型语言:

    源代码不是直接翻译成机器语言,而是先翻译成中间代码,再由解释器对中间代码进行解释运行。比如Python/JavaScript/Shell等都是解释型语言

c 编译型执行代码需要编译成cpu能认识的二进制码 x86指令集
java 编译型执行编译-->字节码,cpu不能直接运行,只能被Java虚拟机执行
shell 解释型语言执行慢

shell 定义

Shell 也是一种程序设计语言,它有变量,关键字,各种控制语句,有自己的语法结构,利用shell程序设计语 言可以编写功能很强、代码简短的程序。

shell是外壳的意思,就是系统的外壳,我们可以通过shell的命令来控制和操作操作系统,比如linux中的shell命令就包括ls、cd、pwd等等,总结来说shell就是一个命令解释器,他通过接收用户输入的shell命令来启动、停止程序的运行或者对计算机进行控制。

shell分类

[root@linux-server ~]# cat /etc/shells 
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin

默认shell: bash shell
centos中脚本使用的默认shell 为/usr/bin/sh

(1)查看当前正在使用的shell

[root@linux-server ~]# echo $SHELL
/bin/bash

(2)shell的修改

[root@linux-server ~]# vim /etc/passwd

使用场景

Shell 能做什么?

1. 自动化批量系统初始化程序 (update,软件安装,时区设置,安全策略...)#初始化脚本
2. 自动化批量软件部署程序 (LAMP,LNMP,Tomcat,LVS,Nginx)#一键安装la\nmp环境,通过脚本自动上线代码
3. 应用管理程序 (KVM)#通过脚本批量创建虚拟机
4. 日志分析处理程序(PV, UV, 200, !200,grep/awk)
5. 自动化备份恢复程序(MySQL完全备份/增量 + Crond)
6. 自动化信息采集及监控程序(收集系统/应用状态信息,CPU,Mem,Disk,Net,TCP Status,Apache,MySQL)
7. 配合Zabbix信息采集(收集系统/应用状态信息,CPU,Mem,Disk,Net,Apache,MySQL)
8. 9*9乘法表、俄罗斯方块,打印三角形,打印圣诞树,打印五角星,运行小火车,坦克大战,排序实现 
9. Shell可以做任何运维的事情(一切取决于业务需求)

shell特性回顾

  • 文件描述符

    在 shell程序中,最常使用的FD (file descriptor) 大概有三个, 分别是: 
    0: Standard Input (STDIN)
    1: Standard Output (STDOUT)
    2: Standard Error Output (STDERR)
    在标准情况下, 这些FD分别跟如下设备关联:
    stdin(0): keyboard 键盘输入,并返回在前端
    stdout(1): monitor 正确返回值 输出到前端
    stderr(2): monitor 错误返回值 输出到前端
  • 输出/入重定向

    >a.txt
    1>a.txt
    2>a.txt
    &>a.txt
    1>&2
    2>&1
    一般来说, "1>" 通常可以省略成 ">"。
    1>&2(将正确输出重定向到错误输出的文件中)正确返回值传递给2输出通道 &2表示2输出通道,之前如果有定义标准错误重定向到某log文件,那么标准输出也重定向到这个log文件,如果此处错写成 1>2, 就表示把1输出重定向到文件2中.
    2>&1(将错误输出重定向到正确输出的文件中)错误返回值传递给1输出通道, 同样&1表示1输出通道。
  • 案例

    【例1】:当前目录下只有a.txt,没有b.txt
    [root@linux-server ~]# touch a.txt
    [root@linux-server ~]# ls a.txt b.txt 1>file.out 2>&1
    [root@linux-server ~]# cat file.out 
    ls: cannot access b.txt: No such file or directory
    a.txt
    # 现在, 正确的输出和错误的输出都定向到了file.out这个文件中, 而不显示在前端 
    
    【例2】:
    [root@linux-server ~]# cat >> b.txt <<!
    >ni hao a haha
    >!
    [root@linux-server ~]# cat b.txt 
    ni hao a haha
    # 注:这里也可以使用EOF需要成对使用即可!

bash初始化

全局配置文件

用户登录时相关的bash配置文件 (登录脚本)属于全局配置文件(针对系统的配置文件):
/etc/profile 
/etc/profile.d/*.sh 
/etc/bashrc

用户配置文件

  • 个人配置文件

    ~/.bash_profile   #家目录下的.bash_profile文件,专门针对root用户的配置文件
    ~/.bashrc
    
    # profile类的文件: 设定环境变量,运行命令或脚本,用户在登录的时候会自动生效
    # bashrc类的文件: 定义命令别名
  • 用户登录时加载bash配置文件的过程

    (1)登录式shell加载配置文件过程
    ~/.bash_profile --> ~/.bashrc --> /etc/bashrc ---> /etc/profile --> /etc/profile.d/*.sh
    
    #这里的优先级是影响范围最小的优先级最高
    (2)非登录式shell加载配置文件过程(非登录式shell:如su - tom。像通过xshell来登录的就属于登录式的shell)
    ~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh
  • 系统的每个用户设置环境信息Shell设置文件

    (1)/etc/profile(系统级)启动时执行 
    这是系统最主要的shell设置文件,也是用户登陆时系统最先检查的文件,有关重要的环境变量都定义在此,其中包括 PATH,USER,MAIL,HOSTNAME,HISTSIZE,INPUTRC等。而在文件的最后,它会检查并执行/etc/profile.d/*.sh的脚本。
    
    (2)~/.bash_login(用户级)登录时执行 
    如果~.bash_profile文件不存在,则系统会转而读取.bash_login这个文件内容。这是用户的登陆文件,在每次用户登陆系统时,bash都会读此内容,所以通常都会将登陆后必须执行的命令放在这个文件中。
    
    (3)~/.bash_logout 离开时执行如果想在注销shell前执行一些工作,都可以在此文件中设置。 例如:
    # vi ~.bash_logout
    clear
    仅执行一个clear命令在你注销的时候
    
    (4)~/.bash_history(用户级) #这个文件会记录用户先前使用的历史命令。
  • bash shell 特性

    补全  tab键   # yum -y install bash-completion
    历史 ---history
    别名 --alias
    快捷键     --ctrl+c 终止
        --ctrl+z 后台运行
        --ctrl+l 清屏
    前后台作业  ---jobs---bg ---fg
    重定向   ---> >> 2> 2>>  <  &
    管道 -----|
    
    #命令排序执行: ; && ||
    &&:逻辑与,前面执行成功,后面才执行。前面命令执行失败,后面命令也不执行
    ||:逻辑或,前面执行失败,后面执行,前面命令执行成功,后面不执行。
    ;:从左往右按顺序执行,不管前面执行成功与否,后面都执行
    
    通配符:[] {} ? *
    正则表达式 脚本
  • 历史命令

    [root@linux-server ~]# history
    调用历史命令 
      上下健
      !关键字
      !历史命令行号
      !! 执行上一条命令
      !$ 上一条命令的最后一个参数
    esc . 上一条命令的最后一个参数
    Ctrl+r 在历史命令中查找,输入关键字调出之前的命令
    
    # 小小技巧:显示历史命令执行时间 
    1.设置变量:
    [root@linux-server ~]# vim /etc/profile    #在最后添加
    HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S" 
    [root@linux-server ~]# source /etc/profile  #让设置的环境变量生效
    
    2.再次执行history查看结果
  • 别名

    [root@linux-server ~]# alias
    设置别名 
    临时设置
    [root@linux-server ~]# aa=88
    [root@linux-server ~]# echo $aa
    88
    永久设置
    # vim /root/.bashrc
    # source /root/.bashrc  #让文件生效
  • Bash 部分快捷键

    Ctrl+a  # 切换到命令行开始(跟home一样,但是home在某些unix环境下无法使用) 
    Ctrl+u  # 清除剪切光标之前的内容
    Ctrl+k  #清除剪切光标之后的内容
    ctrl+y  # 粘贴刚才所删除的字符
    Ctrl+r  # 在历史命令中查找,输入关键字调出之前的命令
    Ctrl+l  # 清屏
    Ctrl+c  # 终止
    Ctrl+e  # 切换到命令行末尾

通配符置换

在 Shell命令中,通常会使用通配符表达式来匹配一些文件
*,?,[],{}

【案例1】:
字符          含义                     实例
*       #匹配 0 或多个字符               a*b a与b之间可以有任意长度的任意字符, 也可以一个也没有, 如aabcb, axyzb, a012b, ab。

?       #匹配任意一个字符                a?b a与b之间必须也只能有一个字符, 可以是任意字符, 如aab, abb, acb, a0b 。

[list]  #匹配 list 中的任意单一字符       a[xyz]b a与b之间必须也只能有一个字符, 但只能是 x 或 y 或 z, 如: axb, ayb, azb 。

[!list] #匹配 除list 中的任意单一字符      a[!0-9]b a与b之间必须也只能有一个字符, 但不能是阿拉伯数字, 如axb, aab, a-b。

[c1-c2] #匹配 c1-c2 中的任意单一字符      如:[0-9] [a-z] a[0-9]b 0与9之间必须也只能有一个字符 如a0b, a1b... a9b。

{string1,string2,...} #匹配 sring1 或 string2 (或更多)其一字符串 a{abc,xyz,123}b a与b之间只能是abc或xyz或123这三个字符串之一。
【案例2】:
# * ?
[root@linux-server tmp]# rm -rf ./*
[root@linux-server tmp]# touch aabcb axyzb a012b ab acb
[root@linux-server tmp]# ls
a012b  aabcb  ab  acb  axyzb
[root@linux-server tmp]# ls a*b
a012b  aabcb  ab  acb  axyzb
[root@linux-server tmp]# ls a?b
acb

# [] 
[root@linux-server tmp]# rm -rf ./*
[root@linux-server tmp]# touch axb ayb azb axyb
[root@linux-server tmp]# ls
axb  axyb  ayb  azb
[root@linux-server tmp]# ls a[xy]b
axb  ayb
[root@linux-server tmp]# ls a[!xy]b
azb
[root@linux-server tmp]# ls a[!x]b
ayb  azb

# []
[root@linux-server tmp]# rm -rf ./*
[root@linux-server tmp]# touch a0b a1b a9b
[root@linux-server tmp]# ls a[0-9]b
a0b  a1b  a9b

# {}
[root@linux-server tmp]# rm -rf ./*
[root@linux-server tmp]# touch aabcb axyzb a012b ab
[root@linux-server tmp]# ls a{abc}b  #没有“,”,不能识别是通配符
ls: cannot access a{abc}b: No such file or directory
[root@linux-server tmp]# ls a{abc,xyz}b
aabcb  axyzb
[root@linux-server tmp]# ls a{abc,xyz,012}b
a012b  aabcb  axyzb

shell脚本规范

[root@linux-server ~]# vim helloworld.sh   ---.sh代表这个文件是个shell脚本,其实其扩展名可有可无,只是对于拓展名后缀,如果省略.sh,那么就不易判断该文件是否为shell脚本
1. #!/usr/bin/env bash ---shebang蛇棒, 解释器, 翻译 2. #
2. #
3. # Author: soso666
4. # Email: soso666@163.com           ---这就是注释, 你没看错
5. # Github: https:github.com/soso666
6. # Date: 2019/12/24
7. printf "hello world\n"

功能说明:打印hello world
[root@linux-server ~]# sh helloworld.sh 
hello world
[root@linux-server ~]# chmod +x helloworld.sh 
[root@linux-server ~]# ./helloworld.sh 
[root@linux-server ~]# /root/helloworld.sh 
hello world

第一行: “#!/usr/bin/env bash”叫做shebang, shell语法规定shell脚本文件第一行为整个文件的解释器
第二行: 为“#”开头的行为注释行默认不会被程序所读取, 用来说明文件及标定所属人员使用, 也可用来解释程序
第七行: 为格式化打印语句printf, printf可以把后面的“hello world”打印到指定的终端中, \n 为换行符

bash 脚本测试:
    -x 
    -n
    -v
# 用解释器(bash)来执行脚本时,该脚本可以不需要执行权限的
1.这将执行该脚本并显示所有变量的值
[root@linux-server ~]# sh -x /root/helloworld.sh
+ printf 'hello world\n'
hello world
2.不执行脚本只是检查语法模式,将返回所有错误语法
[root@linux-server ~]# sh -n /root/helloworld.sh
3.执行脚本前把脚本内容显示在屏幕上
[root@linux-server ~]# sh -v /root/helloworld.sh
#!/usr/bin/env bash
#
# Author: soso666
# Email: soso666@163.com
# Github: https:github.com/soso666
# Date: 2019/12/24
printf "hello world\n"
hello world

变量的类型

分为:预定义变量、环境变量、自定义变量、位置变量

变量:bash作为程序设计语言和其它高级语言一样也提供使用和定义变量的功能,简单说就是让一个特定的字符串代表不固定的内容 a=123,echo $a

预定义变量

预定义的特殊变量有着特殊的含义,用户不可以更改(bash自带的变量),所有的预定义变量都由$符号和另外一个符号组成,常用的预定义特殊变量如下:

$$ 当前正在进行的进程PID
$! 上一个后台进程的PID (wait命令中使用,后面讲)
$? 命令执行后的返回状态.0 为执行正确,非 0 为执行错误 
$# 位置参数的数量(实际中就在脚本里写)
$* 所有位置参数的内容(实际中就在脚本里写)
$@ 显示所有的参数(注意是显示所有参数,也就是说除了位置参数,还有定义的其他参数也会被计算在内。实际中就在脚本里写)
【案例1】:$
[root@linux-server ~]# echo $?   最后一次执行的命令的返回状态。如果这个变量的值为 0,则证明上一条命令正确执行;如果这个变量的值为非 0 ,则 证明上一条命令执行错误
[root@linux-server ~]# echo $$   当前进程的进程号PID(即我当前运行的echo命令进程PID)
[root@linux-server ~]# echo $!   后台运行的最后一个进程的进程号(PID)
[root@linux-server ~]# ls
anaconda-ks.cfg  a.txt  b.txt  file.out  helloworld.sh  #ls命令正确执行
[root@linux-server ~]# echo $?
0   #返回值为0,证明上一条命令正确执行

【案例2】:输出当前进程的PID
[root@linux-server ~]# vim variable.sh
#!/bin/bash
echo "The current process is $$"    
[root@linux-server ~]# bash variable.sh
The current process is 1416    #这个PID就是variable.sh脚本执行时生成的进程的PID

【案例3】:输出上一个后台进程的PID
[root@linux-server ~]# sleep 3000 &
[1] 1418 
#符号"&"的意思是把命令放入后台执行 
[root@linux-server ~]# echo $!
1418

自定义变量

就是自己设置的变量只能在当前终端和脚本中使用。

语法:变量名称=值

# =(赋值符号):前后不能有空格;
# 值: 所有的字符串和数字都可以;
# 引用变量: $变量名 或 ${变量名}。
# 变量名称:只能由字母,数字,下划线组成,不能以数字开头;
# 注意:应该让变量名称有意义;
【案例1】:自定义变量
[root@linux-server ~]# a=100
[root@linux-server ~]# echo $a
100
[root@linux-server ~]# echo $aa     # 这里输出为空,因为解释器认为aa是变量,所以要使用变量要先提前赋值。
[root@linux-server ~]# echo ${a}a   # 这里就会把{a}看做是变量了
100a

查看变量: echo $变量名
取消变量: unset 变量名。仅在当前shell中有效

环境变量

shell在开始执行时已经定义好的,就是系统执行环境的一些设置

export  变量名 #使自定义的变量成为环境变量,才使用这个参数。环境变量拥有可继承性:export之后就拥有继承性环境变量可以被向下继承
# env  #env是 environment (环境) 的简写,所有的环境变量(包含自定义的环境变量)
# set  #列出系统中所有的变量,包括自定义的变量 

# 临时生效
[root@linux-server ~]# IPADDR=192.168.1.1
[root@linux-server ~]# echo $IPADDR
192.168.1.1

# 永久生效
写到4个登陆脚本中 ~/.bashrc ~/profile 更好放在/etc/profile.d/目录下建立独立的环境变量配置文件
[root@linux-server ~]# vim /etc/profile.d/test.sh
IPADDT=192.168.1.1
[root@linux-server ~]# source /etc/profile.d/test.sh  #让环境变量生效
[root@linux-server ~]# echo $IPADDT
192.168.1.1

# 常用环境变量:USER UID HOME HOSTNAME PWD PS1 PATH

# PATH:存储所有命令所在的路径
#子进程 仅会继承父 shell 的环境变量, 不会继承父 shell 的自定义变量
[root@localhost ~]# bash           # 打开一个子 shell
[root@localhost ~]# export a=hello # 在 子 shell 声明一个环境变量
[root@localhost ~]# bash           # 在子 shell 中再打开一个 子 shell
[root@localhost ~]# echo $a        # 变量可以生效
hello
[root@localhost ~]# exit           # 退出 子 shell 的 子 shell
exit
[root@localhost ~]# exit           # 退出 子 shell
exit
[root@localhost ~]# echo $a        # 在当前 shell 中, 其子 shell 声明的环境变量是无效的(即子 shell 声明的环境变量在父shell中是不能用的)

位置变量

位置变量也叫位置参数:在脚本代码中调用通过命令行传递给脚本的参数
$1 $2 $3 $...   #分别对应传递给脚本内容里面的第1、第2等参数...
【案例1】:
# /test.sh start       #start是第1个位置参数
#/test.sh 2 3 5 hello  #2是第1个位置参数,3是第2个位置参数...依次类推

【案例2】:
[root@linux-server ~]# cd /opt/test/script/
[root@linux-server script]# vim weizhi.sh
#!/usr/bin/bash
echo 我的第一个位置参数是:$1 
echo 我的第二个位置参数是:$2 
echo 我的第三个位置参数是:$3 
echo 我的第四个位置参数是:$4 
echo 一共有 $# 个位置参数 
echo 你输入的参数分别是:$*
[root@linux-server script]# chmod +x weizhi.sh 
[root@linux-server script]# ./weizhi.sh 1 3 4 6 
我的第一个位置参数是:1
我的第二个位置参数是:3
我的第三个位置参数是:4
我的第四个位置参数是:6
一共有 4 个位置参数
你输入的参数分别是:1 3 4 6

简单脚本练习

【案例1】:编写一个shell脚本,用于搜集其执行主机的信息,打印结果如下: 
[root@linux-server ~]# mkdir /opt/test/script
[root@linux-server ~]# cd /opt/test/script
[root@linux-server script]# vim test.sh
[root@linux-server script]# chmod +x test.sh
[root@linux-server script]# ./test.sh 
现在的时间是: 2020-08-22-17:34:03
当前的用户是: root
当前的用户标识: 0
当前的主机名称是: linux-server
当前可用网卡IP是: 192.168.246.148/24
##脚本源码如下
#!/usr/bin/bash
# 获取主机基本信息
time=`date +%F-%T`
ip=`ip a | grep ens33 | awk 'NR==2 {print $2}'`
echo "现在的时间是:" $time
echo "当前的用户是:" $USER
echo "当前的用户标识:" $UID
echo "当前的主机名称是:" $HOSTNAME
echo "当前可用网卡IP是:" $ip

【案例2】:编写一个脚本实现收集主机的基本信息,最后脚本还会将这些信息写入一个日志文件.
[root@linux-server script]# vim xinxi.sh
#!/bin/bash
#获取主机基本信息
centime=`date '+%Y-%m-%d %H:%M:%S'`
nowtime=`uptime |awk '{print $1}'`
username=$USER
verage=`uptime |awk -F',' '{print $3,$4,$5}'`
myname=xuange
cat >>file1.txt <<EOF
echo "时间:$centime"
echo "系统的当前时间是: $nowtime"
echo "系统当前负载: $verage"
echo "当前的用户是: $username"
echo "我的名字是: $myname"
EOF
[root@linux-server script]# chmod +x xinxi.sh 
[root@linux-server script]# ./xinxi.sh 
[root@linux-server script]# cat file1.txt

【案例3】:取当前系统分区剩余空间:
[root@linux-server script]# df -Th | awk 'NR==6 {print $5}'
489M

【案例4】:取当前系统剩余内存:
[root@linux-server script]# echo "现在的剩余内存是:"`free -m |awk 'NR==2{print $4}'`
现在的剩余内存是:16G

【案例5】:取当前cpu平均负载:
方式一:cut
[root@linux-server script]# echo 现在cpu的`uptime | cut -d, -f3-` #-d指定分隔符,-f指定显示区域,3-第三列以后(包括第三列)
现在cpu的 load average: 0.00, 0.01, 0.05
方式二:awk
[root@linux-server script]# echo 现在cpu的`uptime | awk -F "," '{print $3,$4,$5}'`
现在cpu的 load average: 0.00 0.01 0.05

变量运算

运算符

算式运算符:+、-、、/、()、%取余(取模),如:(5+3)\2

运算方式

shell的运算方式有:$(()) $[] expr

【案例1】:$(())
# echo $(( 5+2-(3*2)/5 )) 
6
# echo $(((3*2)/5))
1

【案例2】:$[]
# echo $[ 5 + 2 - (3*2)/5 ]   注意和小括号对比
6 

【案例3】:expr
# expr 5 + 3    注意:运算符号两边的空格必须写
8
[ 乘法运算 ]:
[root@linux-server script]# expr 5 \* 3
15
[root@linux-server script]# expr 5 '*' 3
15

【脚本案例】:
[root@localhost ~]# vim test1.sh
#!/usr/bin/bash
a=2
b=13
echo "$a和$b的和是: $(( $a + $b ))"
echo "$a乘$b的值是: $(( $a * $b ))"
echo "$a和$b的差是: $(( $a - $b ))"
echo "$a和$b的商是: $(( $b / $a ))"
echo "$a和$b的余是: $(( $b % $a ))"

#脚本中常用的方式
echo "$a和$b的和是: `expr $a '+' $b`"

产生随机数

【取1到6的随机数(包括1和6)】:
# echo $RANDOM
# echo $(($RANDOM % 6 + 1))
# echo $[$RANDOM % 6 + 1]   # 1-6的随机数(包含1和6)
5 
# echo $[$RANDOM % 6]       # 0-5的随机数(包含0和5)
0
【取1-10之间的随机数(包括1和10)】:
# echo $(($RANDOM % 10 + 1))
5
[root@linux-server script]# vim sjs.sh
#!/bin/bash
echo $(($RANDOM % 50 + 1 )) 
#这串代码实现了随机生成从1~50之间是数

#这串代码特别简单,就是利用RANDOM这个随机数生成器进行取余就能够实现,至于为什么取余时需要+1是因为在取余时如果被整除那么余数会是0,这样就不在限定范围内了

浮点运算

bash本身不能做小数计算:需要bc命令转换

# yum install -y bc   # 安装bc
# echo "2.6*4" | bc   # 可以不用引号
# echo "2^4" | bc     # 可以不用引号

变量引用

  • 完全引用

    完全引用:'' #强引 硬引  #指的是被引号包围起来的变量名不会进行不会进行解析,原样变量名原样输出,这种方式比较适合定义显示纯字符串的情况,不希望解析变量、命令等的场景。
  • 部分引用

    部分引用:"" #弱引 软引  #指的是被引号包围起来的变量名会先进行解析,然后将变量的解析结果输出来。这种方式适合字符串中附带有变量和命令并且想将其解析后再输出的变量定义。

转义:\
当一个字符被引用时,其特殊含义被禁止,把有意义的变的没意义,把没意义的变的有意义,作用类似于完全引用。

[root@linux-server script]# echo you now $1250
you now 250
[root@linux-server script]# echo you now \$1250
you now $1250
  • 案例

    【案例1】:
    [root@linux-server script]# num=1
    [root@linux-server script]# echo 1901班有$num个女生
    1901班有1个女生
    [root@linux-server script]# echo "1901班有$num个女生"
    1901班有1个女生
    [root@linux-server script]# echo '1901班有$num个女生'
    1901班有$num个女生
    
    【案例2】:
    # vim a.sh
    #!/usr/bin/bash
    echo 'echo $USER' >> b.sh
    ======================================================================
    #读取用户标准输入:read 
    read:功能就是读取键盘输入的值,并赋给变量 
    #read -t 5 var
    #read -p "提示信息" var
    read后面的变量var可以只有一个,也可以有多个,这时如果输入多个数据,则第一个数据给第一个变量,第二个数据给第二 个变量,如果输入数据个数过多,则最后所有的值都给最后一个变量
    
    #!/usr/bin/bash
    read -p "请输入你的用户名和密码还有你的年龄: " name pass age
    echo "你的名字是 $name"
    echo "你的密码是 $pass"
    echo "你的年龄是 $age"
    
    【案例3】:
    [root@linux-server script]# vim readtest.sh
    #!/bin/bash
    # read test
    read -p "请输入你的银行卡帐号" num 
    read -p "请在五秒内输入密码" -t 5 pass 
    echo "你的密码错误!"
    [root@linux-server script]# ./readtest.sh
    
    【案例4】:
    [root@linux-server script]# vim readtest2.sh
    #!/bin/bash
    read -p "Do you want to continue [Y/N]? " w 
    case $w in
    Y|y)
      echo "fine ,continue";;
    N|n)
      echo "ok,good bye";;
    *)
      echo "error choice";;
    esac
    exit 0
    [root@linux-server script]# chmod +x readtest2.sh
    [root@linux-server script]# ./readtest2.sh
    
    【案例5】:使read命令中输入的数据不显示在监视器上"(-s参数)"
    [root@linux-server script]# vim readtest3.sh
    #!/bin/bash
    read -s -p "Enter your password: " pass 
    echo "your password is $pass"
    exit 1
    [root@linux-server script]# chmod +x readtest3.sh
    [root@linux-server script]# ./readtest3.sh
    # 取消屏幕回显
    [root@linux-server script]# stty -echo #回车测试
    [root@linux-server script]# stty echo  #恢复回显
    
    【案例6】:显示变量长度
    [root@linux-server script]# a=123
    [root@linux-server script]# echo ${#a}   #表示$var的长度
    3
    
    【案例7】:
    [root@linux-server script]# cat d.sh
    echo 1.配置yum客户端
    echo 2.添加A记录
    echo 3.一键安装lamp环境
    echo 4.一键配置静态IP
    read -p "请选择你想使用的功能(1/2/3/4):" num
    con_ip(){
    echo 这是配置IP地址的小工具
    }
    case $num in
          1):
          ;;
          2):;;
          3):
          ;;
          4)con_ip
          ;;
          *)
          echo "你输入的不正确!请按提示输入"
          ;;
    esac
    [root@linux-server script]# chmod +x d.sh 
    [root@linux-server script]# ./d.sh

脚本运行

(1)创建bash脚本(shell脚本)

1.创建脚本文件 
  指定命令解释器
  注释
  编写bash指令集合 
2.修改权限(+x)

(2)bash脚本执行

# chmod +x script
# ./scripts
# /shelldoc/scripts
# source ./scripts 使用当前shell执行 比如cd /tmp会改变当前shell环境,但是其他的方式不会 
# bash scripts

变量置换与截取

命令替换

注意是命令执行结果的替换。

取命令结果用。把命令的结果拿出来
[root@linux-server ~]# a=`date +%m%d`   #把命令“date +%m%d”执行的结果取出,赋给变量a
[root@linux-server ~]# echo $a
1225
[root@linux-server ~]# a=$(date +%m-%d)
[root@linux-server ~]# echo $a
12-25

#反引号亦可用$() 代替

变量替换

注意是变量的替换。

  • 法一

    一 ${parameter:-word}
    若 parameter 为空或未设置,则用 word 代替 parameter 进行替换,parameter 的值不变。若 parameter 不为空,则不替换,parameter 的值不变。  
    # unset b
    # echo ${b:-3} 
    -3
    # echo $b
    #
    
    二 ${parameter:=word}
    若 parameter 为空或未设置,则用 word 代替 parameter 进行替换,parameter 的值改变,若 parameter设置了,则不替换,parameter的值不变 
    # unset b
    # echo ${b:=3}
    3
    # echo $b
    3
    #
    
    三 ${parameter:+word}
    若 parameter 设置了值,则用 word 代替 parameter 进行替换,parameter 的值不变 
    # unset b    # 若b为空,则不会被word替换
    
    # echo ${b:+3}   # b设置了值,则会被word替换,但b保持不变
    3
    # echo $b
    2
    
    【脚本案例】:
    [root@localhost ~]# vim mysql.sh
    #!/usr/bin/bash
    read -p "请选择你要安装的mysql版本,默认为5.7  " var
    echo "默认的mysql版本为${var:-5.7}"
    echo "你选择的版本是$var"
  • 法二

    #变量内容的替换(只是被临时替换,a的值保持不变)
    【案例1】:
    [root@linux-server ~]# a=123456123789
    [root@linux-server ~]# echo ${a/1/}    #第一次匹配的1被替换为空
    23456123789
    [root@linux-server ~]# echo ${a/1/0}   #第一次匹配到1替换成0
    023456123789
    [root@linux-server ~]# echo ${a//1/}   #全局的匹配的1被替换为空
    2345623789                 
    [root@linux-server ~]# echo ${a//1/x}  #全局匹配到1替换成x
    x23456x23789
    
    【案例2】:
    file=/dir1/dir2/dir3/my.file.txt
    ${file#*/}:  拿掉第一条 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt 
    ${file##*/}: 拿掉最后一条 / 及其左边的字符串:my.file.txt 
    ${file#*.}:  拿掉第一个 . 及其左边的字符串:file.txt
    ${file##*.}: 拿掉最后一个 . 及其左边的字符串:txt
    ${file%/*}:  拿掉最后条 / 及其右边的字符串:/dir1/dir2/dir3
    ${file%%/*}: 拿掉第一条 / 及其右边的字符串:(空值)
    ${file%.*}:  拿掉最后一个 . 及其右边的字符串:/dir1/dir2/dir3/my.file
    ${file%%.*}: 拿掉第一个 . 及其右边的字符串:/dir1/dir2/dir3/my
    
    【记忆的方法为】:
    # 是去掉左边(在键盘上 # 在 $ 之左边)
    % 是去掉右边(在键盘上 % 在 $ 之右边) 
    单一符号是最小匹配;两个符号是最大匹配(贪婪匹配)。

变量截取

(1)语法

${变量#关键词}  若变量内容从头开始的数据符合『关键词』,则将符合的最短数据切除
${变量##关键词} 若变量内容从头开始的数据符合『关键词』,则将符合的最长数据切除
${变量%关键词}  若变量内容从尾向前的数据符合『关键词』,则将符合的最短数据切除
${变量%%关键词} 若变量内容从尾向前的数据符合『关键词』,则将符合的最长数据切除
${变量/旧字符串/新字符串} 若变量内容符合『旧字符串』则『第一个旧字符串会被新字符串替代』
${变量//旧字符串/新字符串} 若变量内容符合『旧字符串』则『全部的旧字符串会被新字符串替代』

(2)索引及切片

[root@linux-server ~]# a=12345678
[root@linux-server ~]# echo ${a:5}    #从从左往右第5位开始截取,留下后三位 
678
[root@linux-server ~]# echo ${a:3:4}  #从第3位开始截取,留下后四位的,剩下的都不要。
4567
[root@linux-server ~]# echo ${a:2:-1} #从左往右第2位开始截取,从右往左截取第一位
34567
[root@linux-server ~]# echo ${a:2:-2}
3456

【案例】:
[root@localhost ~]# vim test11.sh
#!/usr/bin/bash
read -s -p "请输入您的手机号  " phone
echo
echo "你的手机号是 $phone"
echo "手机号后四位是 ${phone:7}"

(3)变量内容的删除

[root@newrain ~]# echo ${url#*.}   从前往后匹配到“.”最短匹配
sina.com.cn
[root@newrain ~]# echo ${url##*.}  从前往后匹配到“.”,最长匹配
cn
[root@newrain ~]# echo ${url%.*}   从后往前匹配到“.”,最短匹配
www.sina.com
[root@newrain ~]# echo ${url%%.*}  从后往前匹配到“.”,最长匹配
www
[root@newrain ~]# echo ${url#a.}    #不加*
www.sina.com.cn
[root@newrain ~]# echo ${url#*a.}   #加*
com.cn

【脚本案例】:
[root@localhost ~]# vim mail.sh
#!/usr/bin/bash
read -p "请输入你的邮箱 " mail
echo "你的邮箱是$mail"
echo "你的邮箱服务器是${mail#*@}"
mail_host=${mail#*@}
case $mail_host in
        163.com)
        echo "网易服务器"
        ;;
        126.com)
        echo "126服务器"
        ;;
        qq.com)
        echo "qq邮箱"
        ;;
        *)
        echo "您输入的邮箱不正确"
        exit 2
esac

【参数解释】:
*:表示全部字符。
%:最短尾匹配;
%%:最大尾匹配
%:从右往左
#:从左往右
用冒号截取:echo $a: : :
从哪里截取留那里。

总结:变量截取时可用冒号(:)、(#)、(%)来截取(删除)

(4)变量长度

[root@linux-server ~]# url=www.sina.com.cn 
[root@linux-server ~]# echo ${#url} #获取变量的长度 
15
[root@linux-server ~]# echo ${url}  #正常显示变量 
www.sina.com.cn

basename & dirname

  • basename 命令:取文件名

    [root@linux-server ~]# temp=/home/temp/1.test
    [root@linux-server ~]# base=basename $temp
    [root@linux-server ~]# echo $base
    1.test
  • dirname 命令:取目录名

    [root@linux-server ~]# temp=/home/temp/1.test
    [root@linux-server ~]# dir=dirname $temp
    [root@linux-server ~]# echo $dir
    /home/temp

    ---END

版权声明:除特殊说明,博客文章均为cuckooyang原创,依据CC BY-SA 4.0许可证进行授权,转载请附上出处链接及本声明。 | 博客订阅:RSS | 广告招租:留言板 | 博客VPS |
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇