shell基础编程

初始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
/usr/bin/sh
/usr/bin/bash
​
#默认shell: bash shell(/bin/sh实际上是链接到/bin/bash的)
#centos中脚本使用的默认shell 为/usr/bin/sh  
​
[root@linux-server ~]# echo $SHELL #查看当前用户所使用的默认Shell的路径
/bin/bash
​[root@linux-server ~]# echo $0     #查看当前正在运行的Shell的名称
-bash                  ##登录shell
bash                   ##非登录shell

[root@linux-server ~]# vim /etc/passwd  编辑登录shell

使用场景

Shell 能做什么?
1. 自动化批量系统初始化程序 (update,软件安装,时区设置,安全策略...)---初始化脚本
2. 自动化批量软件部署程序 (LAMP,LNMP,Tomcat,LVS,Nginx)---自动化安装脚本
3. 应用管理程序 (KVM)---批量创建虚拟机、管理虚拟机。
4. 日志分析处理程序(PV, UV, 200, !200,grep/awk)----akw、sed、grep
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 和ansible---批量自动化工具--自动化运维--ansible

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输出通道.
​
例子. 当前目录下只有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这个文件中, 而不显示在前端

bash 初始化

用户登录Linux时需要执行的几个文件:(登录shell/etc/profile ->/etc/profile.d/*.sh -> (~/.bash_profile | ~/.bash_login | ~/.profile) -> ~/.bashrc -> /etc/bashrc -> ~/.bash_logout
​
全局配置,不管是哪个用户,登录时都会读取该配置文件(系统级别):
/etc/profile 
/etc/profile.d/*.sh 
/etc/bashrc
​
.bash_profile、.profile和.bash_login
当登录到系统时,如果是登录shell(通过SSH登录或在控制台登录输入用户名和密码),它会查找.bash_profile|.profile|.bash_login中的一个,并且只读取第一个找到的文件。这些文件主要用于设置环境变量和执行用户登录时需要运行的命令。
​
~/.bash_login(用户级)登录时执行 
   这是用户的登陆文件,在每次用户登陆系统时,bash都会读此内容,所以通常都会将登陆后必须执行的命令放在这个文件中。
~/.bash_logout(用户级)退出登陆时执行 
    离开时执行,如果想在注销shell前执行一些工作,都可以在此文件中设置。 
​
非登录shell启动文件顺序(读取配置文件顺序):
~/.bashrc ->/etc/bashrc
​
~/.bash_profile
~/.bashrc
​
#profile类的文件: 设定环境变量,运行命令或脚本,用户在登录的时候会自动生效
#bashrc类的文件: 定义命令别名
​# cp /etc/skel/.bash_profile .  ##配置登录用户的bash shell环境
​# source .bash_porfile

~/.bash_history(用户级) #这个文件会记录用户先前使用的历史命令。

# su jack: 这个命令简单地切换到用户 jack的身份,但不切换到他的环境变量。
# su - jack: 这个命令不仅切换到用户jack的身份,还切换到他的环境变量。

bash常用命令

补全  tab键   #yum -y install bash-completion
历史--history
别名---alias
快捷键---ctrl+c+l
前后台作业---jobs fg bg &
重定向 > >> <
管道 ---|
#命令排序执行: ; && ||

通配符:[] {} ? *
正则表达式 脚本

cd:切换当前工作目录。
pwd:显示当前工作目录的路径。
echo:输出文本或变量内容到标准输出。
export:设置环境变量。
unset:删除环境变量。
alias:创建命令别名。
source:读取并执行指定文件中的命令。
history:显示命令历史记录。
exit:退出当前Shell会话。
touch:创建空文件或更新文件的时间戳。
mkdir:创建目录。
rmdir:删除空目录。
rm:删除文件或目录。
cp:复制文件或目录。
mv:移动或重命名文件或目录。
ls:列出目录内容。
cat:显示文件内容。
grep:在文件中查找指定模式。
wc:统计文件或输入中的行数、单词数和字节数。
chmod:修改文件或目录的权限。
chown:修改文件或目录的所有者。
chgrp:修改文件或目录的所属组。
find:在指定路径下查找文件。
tar:打包和解包文件。
gzip:压缩文件。
gunzip:解压缩文件。
man:显示命令的帮助文档。
which:查找指定命令的路径。
read:从标准输入读取一行文本。
[root@linux-server ~]# history  #查看历史命令
调用历史命令 
    上下健
    !关键字
    esc . 上一条命令的最后一个参数

[root@linux-server ~]# alias   #查看别名

[root@linux-server ~]# vim /etc/profile     #设置变量:显示历史命令执行时间
HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S"          #在末尾添加
[root@linux-server ~]# source /etc/profile  #让设置的环境变量生效
2.再次执行history查看结果

Bash 部分快捷键

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

通配符置换

#在 Shell命令中,通常会使用通配符表达式来匹配一些文件:*,?,[],{}
​例:
字符          含义                     实例
*          匹配 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 a与b之间必须也只能有一个字符 如a0b, a1b... a9b。
{s1,s2,...} 匹配s1或s2等其一字符串        a{abc,xyz,123}b a与b之间只能是abc或xyz或123这三个字符串之一。
[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脚本
#!/usr/bin/env bash ##  或#!/bin/bash,shebang蛇棒, 解释器, 翻译
# Author: soso666
# Email: soso666@163.com           
# Github: https:github.com/soso666
# Date: 2019/12/24                 ##注释, 规范要求注明作者、日期、联系方式等
echo "hello world"                 ##功能说明:打印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脚本文件第一行为整个文件的解释器
第二行: 为“#”开头的行为注释行默认不会被程序所读取, 用来说明文件及标定所属人员使用, 也可用来解释程序
第七行: 为输出打印语句echo, echo可以把后面的“hello world”打印到指定的终端中

bash 脚本测试

1.sh -x
    这将执行该脚本并显示所有变量的值
[root@linux-server ~]# sh -x /root/helloworld.sh
+ echo 'hello world'
hello world
2.sh -n
    不执行脚本只是检查语法模式,将返回所有错误语法
[root@linux-server ~]# sh -n /root/helloworld.sh
3.sh -v
    执行脚本前把脚本内容显示在屏幕上
[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
echo "hello world"
hello world 

变量

变量类型

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

预定义变量

预定义的特殊变量有着特殊的含义,用户不可以更改,所有预定义变量都由$符号和另外一个符号组成,常用的预定义变量(特殊变量)如下:   
  • $0:用于获取当前脚本或命令的名称。
  • $$:用于获取当前进程的PID。
  • $?:用于获取上一个命令的退出状态码,可以用来判断命令是否执行成功。
  • $#:用于获取位置参数的数量,也就是命令行参数的个数。
  • $*:用于获取所有位置参数的内容,可以将所有参数作为一个整体使用。
  • $@:用于显示所有的参数,每个参数都可以单独处理。
  • $!:用于获取上一个后台进程的PID,可以在后台进程执行完后使用wait命令等待该进程结束。
[root@linux-server ~]# echo $? 最后一次执行的命令的返回状态。如果这个变量的值为 0,
则证明上一条命令正确执行;如果这个变量的值为非 0 ,则 证明上一条命令执行错误
[root@linux-server ~]# 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,证明上一条命令正确执行
​
[root@linux-server ~]# sleep 3000 &
[1] 1418 
#符号"&"的意思是把命令放入后台执行 
[root@linux-server ~]# echo $!
1418

自定义变量 

自己设置的变量只能在当前终端和脚本中使用
#定义变量变量名称=值  
#变量名称:只能由字母,数字,下划线组成,不能以数字开头;
        #注意:应该让变量名称有意义;
                = 赋值符号 前后不能有空格 ;
                值: 所有的字符串和数字都可以;
#引用变量: $变量名 或 ${变量名}
#查看变量: echo $变量名
#取消变量: unset 变量名,仅在当前shell中有效
示例:
[root@linux-server ~]# a=100
[root@linux-server ~]# echo $a
100
[root@linux-server ~]# echo $aa     # 这里输出为空,因为解释器认为$aa是变量
[root@linux-server ~]# echo ${a}a
100a

环境变量 

shell在开始执行时已经定义好的,就是系统执行环境的一些设置
# env  #env是 environment (环境) 的简写,所有的环境变量(包含自定义的环境变量)
# set  #列出系统中所有的变量,包括自定义的变量 
# export  变量名 
#使自定义的变量成为环境变量.环境变量拥有可继承性:export之后就拥有继承性环境变量可以被向下继承
临时生效
[root@linux-server ~]# IPADDR=192.168.1.1
[root@linux-server ~]# echo $IPADDR
192.168.1.1
永久生效
写到4个登陆脚本中 ~/.bashrc | ~/profile | /etc/profile.d/*.sh | /etc/profile环境变量配置文件中(前2个用户变量,后两个全局环境变量)
​推荐在/etc/profile.d/*.sh 或/etc/profile 配置
[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:存储所有命令所在的路径

常用环境变量

IFS (Internal Field Separator) 定义了 shell 如何处理空白字符和字段分隔符。通过
修改 IFS 的值,你可以控制 shell 如何解析输入行以及如何将输入行分割成字段。
IFS 的默认值包括空格 ( )、制表符 (\t) 和换行符 (\n)。

1)临时修改 IFS
OLD_IFS="$IFS"      # 保存当前的 IFS 值
IFS=';'             # 修改 IFS
read -a fields <<< "field1;field2;field3"  # 使用修改后的 IFS
for field in "${fields[@]}"; do      # 输出字段
    echo "$field"
done
IFS="$OLD_IFS"      # 恢复 IFS

2)永久修改 IFS 如果你想在整个 shell 会话期间修改 IFS 的值,可以简单地给它赋一个新的值:
IFS=';'

3)awk命令应用
IFS=','    # 将 IFS 设置为逗号
echo "apple,banana,grape" | awk '{print $2}'    # 使用 awk 处理数据

位置变量

位置变量也叫位置参数:在脚本代码中调用通过命令行传递给脚本的参数
$1 $2 $3 $...   #分别对应传递给脚本内容里面的第1、第2等参数
​
例子:
# /test.sh start   #start是第1个位置参数
#/test.sh 2 3 5 hello #2是第1个位置参数,3是第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

 变量的子进程继承

#子进程 仅会继承父 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 声明的环境变量是无效的

变量符号

反引号

在Linux中,``(反引号)是一种命令替换的语法。它用于将命令的输出作为另一个命令的参数或赋值给变量。当在命令中使用时,其中包含的命令会被执行,并将其输出结果取代所在的位置。

练习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
​
​
取当前系统分区剩余空间:
[root@linux-server script]# df -Th | awk 'NR==6 {print $5}'
489M
取当前系统剩余内存:
[root@linux-server script]# echo "现在的剩余内存是:"`free -m |awk 'NR==2{print $4}'`
现在的剩余内存是:16G
​
取当前cpu平均负载:
[root@linux-server script]# echo 现在cpu的`uptime | cut -d, -f3-` #-d指定分隔符,-f指定显示区域,3-第三列以后(包括第三列)
现在cpu的 load average: 0.00, 0.01, 0.05
方式二:
[root@linux-server script]# echo 现在cpu的`uptime | awk -F "," '{print $3,$4,$5}'`
现在cpu的 load average: 0.00 0.01 0.05
练习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

转义

\     
当一个字符被引用时,其特殊含义被禁止,把有意义的变的没意义,把没意义的变的有意义
# echo you now $1250     #输出:you now 250
# echo you now \$1250    #输出you now $1250

变量运算

运算符

整数运算符
+ 加法
- 减法
* 乘法
/ 除法(结果为整数)
% 取模(求余数)
** 幂运算(Bash 4.0及以上版本支持)
关系运算符

用于比较数值,常用于条件语句中

-eq 相等
-ne 不等
-gt 大于
-lt 小于
-ge 大于等于
-le 小于等于
逻辑运算符

用于组合条件表达式。

&&   逻辑与:前面执行成功,后面才执行。前面命令执行失败,后面命令也不执行。
||   逻辑或:前面执行失败,后面执行,前面命令执行成功,后面不执行。
!    逻辑非:取反操作
;    分隔命令:不是逻辑运算符,从左往右按顺序执行,不管前面执行成功与否,后面都执行
字符串运算符
==     字符串相等
!=     字符串不相等
*      字符串重复
+      字符串连接

运算方式 $(())   $[]   expr

$(())和$[]命令的表达式可以直接嵌入在命令中,expr命令需要使用命令替换的方式或将结果赋值给变量。

$(())   
$(())命令是一种Shell的算术展开(arithmetic expansion)的方式,用于执行数学运算,
如加法、减法、乘法、除法等。
基本语法:$((表达式))   其中表达式可以包含变量、数学运算符和括号。例如:
# echo $(( 5+2-(3*2)/5 ))         #输出6
# echo $(((3*2)/5))               #输出1
​
$[]     和$(())类似,只能执行数学运算
# echo $[ 5 + 2 - (3*2)/5 ]       #输出6

expr命令   #注意:运算符号两边的空格必须写
expr命令可以执行数学运算和字符串操作
# expr 5 + 3                  #输出8
# expr 5 \* 3                 #乘法运算:输出15
# expr 5 '*' 3                #输出15
# a=5
# b=7 # echo "$a和$b的和是: `expr $a '+' $b`"
5和7的和是: 12

bc命令
使用 bc命令来进行高级算术运算,如浮点数运算,基本算术运算、对数运算、三角函数运算。
bash本身不能做小数计算:需要bc命令转换 
# yum install -y bc   #安装bc软件包
# echo "2.6*4" | bc   #输出10.4
# echo "2^4" | bc     #输出16

RANDOM函数
# echo $RANDOM                #随机生成0到32767的整数
# echo $(($RANDOM % 6 + 1))   #取1到6之间的随机数
# echo $(($RANDOM % 10 + 1))  #取1-10之间的随机数
​#RANDOM随机数生成器进行取余,实现生成范围内随机数
#取余时需要+1的原因:取余时如果被整除那么余数会是0,这样就不在限定范围内了

变量引用

完全引用和部分引用

完全引用:''   也叫强引  硬引  
当字符串被单引号包围时,所有特殊字符和变量名都会被视为普通文本,不会被Shell解释或展开,原样变量名原样输出,比较适合定义显示纯字符串的情况,不希望解析变量、命令等的场景。
部分引用:""   也叫弱引 软引  
当字符串被双引号包围时,字符串中的变量会被展开,也就是变量名会被替换为变量的值。适合字符串中附带有变量和命令并且想将其解析后再输出的变量定义。
无引号:在没有任何引号的情况下,Shell会尝试解释字符串中的特殊字符和变量名。
[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个女生

变量读取

读取用户标准输入:read

read:功能就是读取键盘输入的值,并赋给变量(var) 
语法:
    read [-options] [varname ...]
[-options]:
-p prompt-string:显示提示信息,然后读取输入。
-t timeout:设置读取输入的超时时间(秒数)。如果在指定的时间内没有输入,read 命令将返回一个非零退出状态。
-s:秘密模式。在读取输入时,不显示输入的字符,常用于密码输入。

[varname ...]:
read后面的变量var可以只有一个,也可以有多个,这时如果输入多个数据,则第一个数据给第一个变量,第二个数据给第二 个变量,如果输入数据个数过多,则最后所有的值都给最后一个变量
​
【实例】
[-p]
#!/usr/bin/bash
read -p "请输入你的用户名和密码还有你的年龄: " name pass age
echo "你的名字是 $name"
echo "你的密码是 $pass"
echo "你的年龄是 $age"
​[-t]
[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
​[-s]
案例2:  #-s 选项 能够使read命令中输入的数据不显示在监视器上
[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

取消屏幕回显

在Shell中取消屏幕回显,通常是在需要用户输入密码或其他敏感信息时使用,因为在这种情况下显示输入的内容是不安全的。stty命令用于设置和报告终端行输入和输出的格式。

stty -echo     取消回显
stty echo      恢复回显

显示变量长度

  • 使用参数扩展来获取变量的长度:使用 ${#variable} 的形式来得到变量值的字符数,这里的 # 符号用于获取变量值的长度。
  • ${#variable} 返回的是字符数,这意味着它也会计算空格、标点符号和其他非字母数字字符。
  • 如果变量未被初始化或其值为空,${#variable} 将返回0,表示变量的长度为0。
[root@linux-server ~]# a=123
[root@linux-server ~]# echo ${#a}   #表示$var的长度
3
[root@linux-server ~]# vim test.sh
#!/bin/bash
empty_var=""                        #定义一个空变量
length=${#empty_var}                #获取变量的长度
# 输出变量的长度
echo "空变量的长度: $length"
[root@linux-server ~]# sh test.sh
空变量的长度: 0

菜单脚本练习 

[root@linux-server ~]# vim d.sh
#!/bin/bash

# 定义一个函数来显示菜单
show_menu() {
    echo "请选择你想使用的功能:"
    echo "1. 配置yum客户端"
    echo "2. 添加A记录"
    echo "3. 一键安装LAMP环境"
    echo "4. 一键配置静态IP"
    echo "5. 退出"
}
# 定义一个函数来配置IP地址
config_ip() {
    echo "这是配置IP地址的小工具"
    # 这里可以添加具体的IP配置代码
}
# 主函数
main() {
    while true; do
        show_menu
        read -p "请输入选项编号(1/2/3/4/5): " num
        case $num in
            1)
                echo "配置yum客户端功能"
                ;;
            2)
                echo "添加A记录功能"
                ;;
            3)
                echo "一键安装LAMP环境功能"
                ;;
            4)
                config_ip
                ;;
            5)
                echo "退出菜单。"
                break
                ;;
            *)
                echo "你输入的不正确!请按提示输入"
                ;;
        esac
    done
}
# 调用主函数
main

[root@linux-server script]# chmod +x d.sh 
[root@linux-server script]# ./d.sh

脚本运行

创建bash脚本(shell脚本)

1.创建脚本文件 
        指定命令解释器
        注释
        编写bash指令集合 
2.修改权限
bash脚本执行
1.直接执行(给脚本执行权限)
# chmod +x yourscript.sh
# ./yourscript.sh           脚本的路径来执行
# /path/to/yourscript.sh    脚本位于当前目录之外,提供完整的路径
2.使用 source 或 . 命令
在当前Shell会话中执行脚本并应用其环境变量更改。
# source yourscript.sh 
# . yourscript.sh
两种方法都是在当前Shell环境中执行脚本,而不是在子Shell中,因此任何环境变量的变化都将保留在当前会话中。
3.bash 
# bash yourscript.sh          脚本的路径来执行
# bash /path/to/yourscript.sh 脚本位于当前目录之外,提供完整的路径

反引号使用

取命令结果用。把命令的结果拿出来
[root@linux-server ~]# a=`date +%m%d`
[root@linux-server ~]# echo $a
1225
[root@linux-server ~]# a=$(date +%m-%d)
[root@linux-server ~]# echo $a
12-25
​
#反引号亦可用$() 代替

 ${}使用

在shell中,${}是一个特殊的语法,用于进行变量替换和变量扩展。它可以用于以下几种情况:

1. 变量替换:
${变量名}:替换为变量的值。
${变量名:-替换值}:如果变量未定义或为空,则使用默认值。
${变量名:=替换值}:如果变量未定义或为空,则将其设置为默认值。
${变量名:+替换值}:如果变量定义且非空,则使用替换值。
${变量名:?错误信息}:如果变量未定义或为空,则输出错误信息并退出。
【实例1】
name=Mike
age=
echo ${name:-John}  # 输出 "Mike",因为name非空
echo ${name:=John}  # 输出 "Mike",因为name非空
echo ${name:+John}  # 输出 "John",因为name非空
echo "Name: ${age:?age is null}"  # 如果age为空,输出age is null并退出


2. 数组变量替换
${数组名[@]}:返回数组的所有元素。每个元素都是单独的词(token),即使它们之间没有空格。
             适合于需要分别处理数组中的每个元素的场合,例如在 for 循环中。
${数组名[*]}:返回数组的所有元素,这些元素被合并成一个字符串,中间由默认的IFS字符分隔。
            适合于需要将数组作为一个整体来处理的场合,例如将数组传递给一个接受多个参数的命令。
${#数组名[@]}:返回数组的元素个数。
${#数组名[*]}:返回数组的元素个数。
【实例2】
fruits=("apple" "banana" "orange")
echo "All fruits: ${fruits[@]}"          # 输出:All fruits: apple banana orange
echo "Fruit count: ${#fruits[@]}"        # 输出:Fruit count: 3

3. 命令替换
${命令}:将命令的输出结果替换为字符串
current_date=$(date +%Y-%m-%d)
echo "Current date is ${current_date}"

变量替换-匹配截取

切片

在Shell中,可以使用切片(slicing)的方式从字符串中提取特定的部分。切片可以用于字符串、数组等数据类型的截取操作。如果切片的长度参数为负数,表示从起始位置开始截取到倒数第几个字符

切片的语法为:${变量名:起始位置:长度} 或者 ${变量名:起始位置}

切片
[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
​
参数解释:
用冒号截取:echo $a: :
              从哪里截取留那里。
​
脚本案例:
[root@localhost ~]# vim test11.sh
#!/usr/bin/bash
read -s -p "请输入您的手机号  " phone
echo
echo "你的手机号是 $phone"
echo "手机号后四位是 ${phone:7}"
​匹配截取
语法:
${变量#关键词}  若变量内容从头开始的数据符合『关键词』,则将符合的最短数据切除
${变量##关键词} 若变量内容从头开始的数据符合『关键词』,则将符合的最长数据切除
${变量%关键词}  若变量内容从尾向前的数据符合『关键词』,则将符合的最短数据切除
${变量%%关键词} 若变量内容从尾向前的数据符合『关键词』,则将符合的最长数据切除
​
参数解释:
*:表示全部字符。
%:最短尾匹配;
%%:最大尾匹配
%:从右往左
#:从左往右
​
例:
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
记忆的方法为:
# 是去掉左边(在键盘上 # 在 $ 之左边)
% 是去掉右边(在键盘上 % 在 $ 之右边) 
单一符号是最小匹配;两个符号是最大匹配(贪婪匹配)。

实战
url=www.sina.com.cn 
echo ${#url}     获取变量的长度 
#输出:15
echo ${url}      正常显示变量   
#输出:www.sina.com.cn
echo ${url#*.}   #*.表示从前往后匹配第一个出现的点号.后的所有字符。 
#输出:sina.com.cn
echo ${url##*.}   ##表示最长匹配,匹配所有前面的字符直到最后一个点号为止 
#输出:cn
echo ${url%.*}   %.*表示从后向前匹配最近的一个点号.保留该点号之前的所有字符
#输出:www.sina.com
echo ${url%%.*}  从后往前匹配到“.”,最长匹配,去掉从最后一个点号到字符串结尾的所有字符  
#输出:www
echo ${url#a.}   不加* 不匹配任何部分,因为字符串不是以"a."开头的 输出:www.sina.com.cn
echo ${url#*a.}  加*匹配任意数量的字符后面跟着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

变量内容的替换
语法
${变量/旧字符串/新字符串} 若变量内容符合『旧字符串』则『第一个旧字符串会被新字符串替代』
${变量//旧字符串/新字符串} 若变量内容符合『旧字符串』则『全部的旧字符串会被新字符串替代』
​
实战
[root@linux-server ~]# a=123456123789
[root@linux-server ~]# echo ${a/1/}    #第一次匹配的被替换
23456123789
[root@linux-server ~]# echo ${a/1/0}  #第一次匹配到1替换成0
023456123789
[root@linux-server ~]# echo ${a//1/}  #全局的匹配被替换
2345623789                 
[root@linux-server ~]# echo ${a//1/x} #全局匹配到1替换成x
x23456x23789
提取路径的文件名部分或目录部分

basename 命令

basename 提取路径中的文件名部分
basename [选项] [路径]
-a:返回所有路径中文件名的列表。
-s 后缀:去除文件名中的指定后缀。
-z:以空字符作为路径分隔符,适用于处理包含空格等特殊字符的路径。
例: 
[root@linux-server ~]# temp=/home/temp/1.test
[root@linux-server ~]# base=`basename $temp`
[root@linux-server ~]# echo $base
1.test

dirname命令 

dirname 提取路径中的目录部分
dirname [选项] [路径]

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

  • 20
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值