当前位置: 首页 > news >正文

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"      # 恢复 IFS2)永久修改 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 ]       #输出6expr命令   #注意:运算符号两边的空格必须写
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的和是: 12bc命令
使用 bc命令来进行高级算术运算,如浮点数运算,基本算术运算、对数运算、三角函数运算。
bash本身不能做小数计算:需要bc命令转换 
# yum install -y bc   #安装bc软件包
# echo "2.6*4" | bc   #输出10.4
# echo "2^4" | bc     #输出16RANDOM函数
# 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; doshow_menuread -p "请输入选项编号(1/2/3/4/5): " numcase $num in1)echo "配置yum客户端功能";;2)echo "添加A记录功能";;3)echo "一键安装LAMP环境功能";;4)config_ip;;5)echo "退出菜单。"break;;*)echo "你输入的不正确!请按提示输入";;esacdone
}
# 调用主函数
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: 33. 命令替换
${命令}:将命令的输出结果替换为字符串
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 in163.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

相关文章:

shell基础编程

初始shell 程序 语言 编程 ---------------------------------- 语言 自然语言:汉语、英语 计算机语言:c语言、c、(java php python go shell) 编译型语言 c c java 解释型语言 php python bash ​ 编译型语言:编译型语言的首先将源代码编译生成机器语言&#xff0c;再由机…...

近期代码报错解决笔记

1.TypeError: ‘bool’ object is not callable 想print("Type of head:", type(entity_emb[head]))&#xff0c;结果报如下错误&#xff1a; 源代码&#xff1a; 因为 print 仍然被当作一个布尔值处理&#xff0c;而不是作为函数调用。这个问题的根源在于 print …...

apache设置ssl代理

<VirtualHost *:8082> ServerName localhost DocumentRoot D:\xampp\htdocs\somgl\dist #证书 SSLProtocol all -SSLv2 SSLCipherSuite DEFAULT:!EXP:!SSLv2:!DES:!IDEA:!SEED:3DES SSLEngine on SSLProxyEngine on SSLProxyVerify…...

数据库中单表的查询(select)

单表查询 所有的查找都会得到一张虚拟表 一、 最简单的查询 SELECT 123; SELECT asd; SELECT 11;二、 从表中获取数据 select 字段名,字段名 from 表名 2.1 全字段查询 SELECT sid,sname,birthday,ssex,classid FROM student; SELECT * FROM student; -- 使用*不利于s…...

Spring源码-BeanFactory类关系层级

BeanFactory 访问Spring bean容器的根接口。 这是bean容器的基本客户端视图;例如{link ListableBeanFactory}和{link org.springframework.beans.factory.config。ConfigurableBeanFactory}可用于特定目的。 这个接口是由包含许多bean定义的对象实现的&#xff0c;每个bean定义…...

Electron 结合 Selenium + chromedriver 驱动服务实现浏览器多开

背景 在调研浏览器多开的过程中&#xff0c;electron 有自带的 browserview&#xff0c;webview&#xff0c;但是上面两个受制于 electron 内核版本限制&#xff0c;升级不够灵活&#xff0c;对新版的网页支持可能不及时&#xff0c;甚至不兼容&#xff0c;必须通过发布新的客…...

手持式气象检测设备:便携科技,气象探测

一、手持式气象检测设备&#xff1a;小巧身躯&#xff0c;大能量 手持式气象检测设备&#xff0c;顾名思义&#xff0c;是一种可以手持操作的气象监测工具。它集成了温度、湿度、气压、风速风向等多种传感器&#xff0c;能够实时获取气象数据&#xff0c;并通过显示屏或手机APP…...

shell 发送邮件脚本(免密)

#!/bin/bash ENV$1 TARGET_VERSION$2 TO$3 # SMTP服务器设置 SMTP_SERVER"邮箱服务地址" SMTP_PORT"25"# 邮件信息 FROM"jenkinsy.com" SUBJECT"Deployment Status Notification" BODY$ENV"发布完成&#xff0c;版本 &#xff1a…...

Web动画(lottie篇)

一、Lottie简介 Lottie是一个库&#xff0c;可以解析使用AE制作的动画&#xff08;需要用bodymovin导出为json格式&#xff09;&#xff0c;支持web、ios、android和react native。在web侧&#xff0c;lottie-web库可以解析导出的动画json文件&#xff0c;并将其以svg或者canva…...

昇思25天学习打卡营第20天|CV-ResNet50图像分类

打卡 目录 打卡 图像分类 ResNet网络介绍 数据集准备与加载 可视化部分数据集 残差网络构建 Building Block 结构 代码实现 Bottleneck结构 代码实现 构建ResNet50网络 代码定义 模型训练与评估 可视化模型预测 重点&#xff1a;通过网络层数加深&#xff0c;感知…...

grep: /etc/mysql/my.cnf: 没有那个文件或目录

当你收到 "grep: /etc/mysql/my.cnf: 没有那个文件或目录" 的错误信息时&#xff0c;这意味着你的系统上可能没有默认的 MySQL/MariaDB 配置文件 /etc/mysql/my.cnf。MariaDB 和 MySQL 可能会使用不同的配置文件路径。下面是一些步骤来帮助你找到正确的配置文件&…...

养猫好物|宠物空气净化器是不是智商税?靠谱猫毛空气净化器推荐

宠物空气净化器是不是智商税&#xff1f;宠物空气净化器是否真有其效&#xff0c;是许多由于要不要买空气净化器养宠人心中的疑惑。作为呼吸科医生&#xff0c;我深知良好空气质量对呼吸道健康的重要性&#xff0c;因此建议所有家庭&#xff0c;尤其是养有猫狗等宠物的家庭&…...

【CPS出版】2024年智能计算与数据分析国际学术会议(ICDA 2024,9月6日-8)

为探讨数据科学和计算智能领域的关键问题&#xff0c;促进相关交流&#xff0c;2024年智能计算与数据分析国际学术会议&#xff08;ICDA 2024)将于2024年9月6日-8日在中国青岛召开。 本届会议拟邀请数据分析和计算智能领域的顶级专家、学者和产业界优秀人才&#xff0c;围绕当前…...

AutoGen框架革新:解锁新闻稿写作的新境界

前言 今天带来的仍然是AutoGen基于AssistantAgent和UserProxyAgent的例子&#xff0c;以帮助大家一起消化目前最前卫的AI应用框架。这是一个AIGC最擅长&#xff0c;因为生成新闻稿嘛&#xff0c;同时又需要利用Agent的一个常规Demo。了解LangChain的同学&#xff0c;会通过对比…...

数据结构之队列详解

1.队列的概念以及结构 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进先出FIFo(Frist in Frist out)的特性 入队列&#xff1a;进行插入才操作的一端称为队尾 出队列&#xff1a;进行删除操作的一…...

[渗透测试] 反序列化漏洞

反序列化漏洞 ​ 序列化&#xff1a;将对象的状态信息转换为可以传输或存储的形式的过程。简单的来说&#xff0c;就是将一个抽象的对象转换成可以传输的字符串 &#xff0c;以特定的形式在进行之间实现跨平台的传输。 序列化大多以字节流、字符串、json串的形式来传输。将对…...

C++ 类型转换 包括C风格的转换、static_cast、const_cast、reinterpret_cast、dynamic_cast、模板特化等

C 类型转换 包括C风格的转换、static_cast、const_cast、reinterpret_cast、dynamic_cast、模板特化等 flyfish 0. 隐式转换&#xff08;Implicit Conversions&#xff09; 隐式转换是编译器自动进行的类型转换&#xff0c;通常在需要将一个类型转换为另一个类型以匹配函数参…...

等保通过标准

等保测评&#xff0c;即信息系统安全等级保护测评&#xff0c;是国家对信息系统安全等级保护的一种评估活动。它涉及到安全管理、安全技术、安全运维等多个方面&#xff0c;旨在评定信息系统是否达到了国家设定的安全等级保护标准。等保测评的通过标准通常会根据信息系统的安全…...

reduceByKey 函数详解

reduceByKey 函数详解 实现原理 reduceByKey 函数主要用于处理分布式数据集。它接收两个操作符作为参数&#xff1a; keySelector&#xff1a;这是一个映射函数&#xff0c;用于从输入元素中提取键。 valueReducer&#xff1a;这是另一个函数&#xff0c;用于将具有相同键的…...

CSI-RS在信道中传输的过程

简单介绍CSI-RS信号生成&#xff0c;在信道中传输和接收的过程 1.载波配置 首先需要配置载波相关的参数 系统带宽和子载波间隔 5G NR中&#xff0c;系统带宽和子载波间隔是两个关键参数&#xff0c;共同决定无线资源的分配和使用 系统带宽 5G NR支持广泛的系统带宽&…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

Fabric V2.5 通用溯源系统——增加图片上传与下载功能

fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...

基于PHP的连锁酒店管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...

离线语音识别方案分析

随着人工智能技术的不断发展&#xff0c;语音识别技术也得到了广泛的应用&#xff0c;从智能家居到车载系统&#xff0c;语音识别正在改变我们与设备的交互方式。尤其是离线语音识别&#xff0c;由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力&#xff0c;广…...

小木的算法日记-多叉树的递归/层序遍历

&#x1f332; 从二叉树到森林&#xff1a;一文彻底搞懂多叉树遍历的艺术 &#x1f680; 引言 你好&#xff0c;未来的算法大神&#xff01; 在数据结构的世界里&#xff0c;“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的&#xff0c;它…...